Настройка staticmethod в Python
-
19-09-2019 - |
Вопрос
Я пытался выделить объект, который содержит ссылки на методы статического класса.Рассол не получается (например, на module.MyClass.foo
) заявляя, что его нельзя мариновать, так как module.foo
не существует.
Я придумал следующее решение, используя объект-оболочку для определения местоположения функции при вызове, сохраняя класс контейнера и имя функции:
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():выведите "готово".
Мои попытки сделать это были безуспешными, в частности, потому, что я не смог извлечь класс owner из foo
функция.Я даже был готов согласиться на явное уточнение (например, @picklable_staticmethod(MyClass)
) но я не знаю ни о каком способе сослаться на MyClass
класс прямо там, где он определяется.
Любые идеи были бы замечательными!
Йонатан
Решение
Кажется, это работает.
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
).Тогда консервирование, распаковка и вызов метода могут выполняться немного быстрее.
Другие советы
Редактировать:изменено после комментария Джейсона.
Я думаю, что python прав, не позволяя травить объект staticmethod - поскольку невозможно травить методы экземпляра или класса!Такой объект имел бы очень мало смысла вне своего контекста:
Проверьте это: Учебное пособие по дескрипторам
import pickle
def dosomething(a, b):
print a, b
class MyClass(object):
dosomething = staticmethod(dosomething)
o = MyClass()
pickled = pickle.dumps(dosomething)
Это работает, и это то, что нужно сделать - определить функцию, настроить ее и использовать такую функцию как staticmethod в определенном классе.
Если у вас есть вариант использования для ваших нужд, пожалуйста, запишите его, и я буду рад обсудить его.