2009-12-16 2 views
2

Я пытался рассолить объект, содержащий ссылки на статические методы класса. Рассол не работает (например, на module.MyClass.foo), заявив, что он не может быть маринован, поскольку module.foo не существует.
я придумал следующее решение, используя объект-оболочку, чтобы найти функцию при вызове, сохранение класса контейнера и функции имя:Травление статического метода в Python

class PicklableStaticMethod(object): 
    """Picklable version of a static method. 
    Typical usage: 
     class MyClass: 
      @staticmethod 
      def doit(): 
       print "done" 
     # This cannot be pickled: 
     non_picklable = MyClass.doit 
     # This can be pickled: 
     picklable = PicklableStaticMethod(MyClass.doit, MyClass) 
    """ 
    def __init__(self, func, parent_class): 
     self.func_name = func.func_name 
     self.parent_class = parent_class 
    def __call__(self, *args, **kwargs): 
     func = getattr(self.parent_class, self.func_name) 
     return func(*args, **kwargs) 

мне интересно, хотя, есть лучше - более стандартный способ - рассолить такой объект? Я не хочу, чтобы внести изменения в глобальной pickle процесса (с использованием copy_reg, например), но следующий шаблон будет велик: класс MyClass (объект): @picklable_staticmethod Защиту Foo(): «сделано» печати

Мои попытки были безуспешными, особенно потому, что я не смог извлечь класс владельца из функции foo. Я даже хотел согласиться на явные спецификации (например, @picklable_staticmethod(MyClass)), но я не знаю, как обращаться к классу MyClass, где он определен.

Любые идеи были бы замечательными!

Yonatan

ответ

5

Это похоже на работу.

class PickleableStaticMethod(object): 
    def __init__(self, fn, cls=None): 
     self.cls = cls 
     self.fn = fn 
    def __call__(self, *args, **kwargs): 
     return self.fn(*args, **kwargs) 
    def __get__(self, obj, cls): 
     return PickleableStaticMethod(self.fn, cls) 
    def __getstate__(self): 
     return (self.cls, self.fn.__name__) 
    def __setstate__(self, state): 
     self.cls, name = state 
     self.fn = getattr(self.cls, name).fn 

Уловка заключается в том, чтобы уловить класс, когда из него получен статический метод.

Альтернативы: вы можете использовать метаклассизацию, чтобы дать всем вашим статическим методам атрибут .__parentclass__. Затем вы можете подкласса Pickler и дать каждому экземпляру подкласса свою собственную таблицу .dispatch, которую затем можно изменить, не затрагивая глобальную таблицу рассылки (Pickler.dispatch). Травление, рассыпание и вызов метода могут быть немного быстрее.

+0

это не сработает, если исходный класс недоступен, который (я думаю) побеждает цель травления и рассыпания статического метода - вы разрешаете его мариноваться, но вам нужен весь класс, чтобы его разложить. –

+0

попробовать, что, например: импорт рассола класса MyClass (объект): @PickleableStaticMethod Защиту DoSomething (а, б): печатающих а, б маринованных = pickle.dumps (MyClass.dosomething) дель MyClass stm = pickle.loads (маринованный) –

+0

Я думаю, я мог бы просто сказать что-то совершенно неправильное там, маринованные работы совершенно разные с funcs, которые я ожидал. игнорировать мои последние два комментария: -/ –

0

EDIT: модифицировано после комментария Джейсона.

Я думаю, что python прав, не позволяя травить объект staticmethod - так как невозможно раскрыть методы экземпляра или класса! Такой объект будет сделать очень мало смысла вне его контекста:

Проверьте это: Descriptor Tutorial

import pickle 

def dosomething(a, b): 
    print a, b 

class MyClass(object): 
    dosomething = staticmethod(dosomething) 

o = MyClass() 

pickled = pickle.dumps(dosomething) 

Это работает, и это то, что должно быть сделано - определить функцию, засолить, и использовать такие функции, как статический метод в определенном классе.

Если у вас есть прецедент для ваших нужд, пожалуйста, запишите его, и я буду рад обсудить его.

+0

Что не сработает, это 'pickle.dumps (MyClass.dosomething)'. –

+0

, тогда вопрос не написан должным образом, OP говорит: «Я пытался раскрыть объект, содержащий ссылки на статические методы класса», в то время как он действительно пытается выбрать статический метод, а не объект, содержащий ссылки на статические методы. –

+0

Позвольте мне пояснить на примере. У меня есть механизм создания задачи.Например: класс MyClass (TaskGenerator): @staticmethod Защиту certain_task(): печать "задача сделать" Защиту generate_task (сам): возвращение FuncTask (MyClass.certain_task) Я хочу замариновать с дробями но в настоящее время не может. Я могу использовать глобальную функцию - и до сих пор - но мне не нравится вынимать ее из своего «правильного места» в пользу поддержки травления. – Yonatan

Смежные вопросы