3

我一直在尝试腌制一个包含对静态类方法的引用的对象。Pickle 失败(例如 on 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例如使用),但以下模式会很棒:class MyClass(object): @picklable_staticmethod def foo(): print "done."

我在这方面的尝试没有成功,特别是因为我无法从foo函数中提取所有者类。我什至愿意接受明确的规范(例如@picklable_staticmethod(MyClass)),但我不知道有什么方法可以直接引用MyClass定义它的类。

任何想法都会很棒!

与那丹

4

2 回答 2

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)。酸洗、解酸和调用该方法可能会快一点。

于 2009-12-16T13:57:50.387 回答
0

编辑:在杰森评论后修改。

我认为python不让腌制静态方法对象是正确的——因为不可能腌制实例或类方法!这样的对象在其上下文之外几乎没有意义:

检查这个:描述符教程

import pickle

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

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

o = MyClass()

pickled = pickle.dumps(dosomething)

这行得通,这就是应该做的——定义一个函数,腌制它,然后在某个类中使用这样的函数作为静态方法。

如果您有需要的用例,请写下来,我很乐意讨论。

于 2009-12-16T13:19:31.477 回答