【问题标题】:Pickling a staticmethod in Python在 Python 中腌制一个静态方法
【发布时间】:2010-12-27 05:18:59
【问题描述】:

我一直在尝试腌制一个包含对静态类方法的引用的对象。 Pickle 失败(例如在 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),但以下模式会很棒: 我的类(对象): @picklable_staticmethod 定义 foo(): 打印“完成”。

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

任何想法都会很棒!

约拿坦

【问题讨论】:

    标签: python static-methods pickle


    【解决方案1】:

    编辑:在 Jason 评论后修改。

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

    检查这个:Descriptor Tutorial

    import pickle
    
    def dosomething(a, b):
        print a, b
    
    class MyClass(object):
        dosomething = staticmethod(dosomething) 
    
    o = MyClass()
    
    pickled = pickle.dumps(dosomething)
    

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

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

    【讨论】:

    • 那么问题写得不正确,OP说“我一直在尝试腌制一个包含对静态类方法的引用的对象”,而他实际上是在尝试腌制一个静态方法,而不是一个对象包含对静态方法的引用。
    • 让我用一个例子来澄清一下。我有一个任务生成机制。例如: class MyClass(TaskGenerator): @staticmethod def certain_task(): print "task done" def generate_task(self): return FuncTask(MyClass.certain_task) 我想腌制生成的任务,但目前不能。我可以使用全局函数 - 并且一直到现在 - 但我不喜欢将其从“正确的位置”取出以支持酸洗。
    • 我承认我仍然不明白您想要做什么,我仍然认为您可能在滥用“静态方法”(在哪里、如何以及为什么你解开这些物体?)
    【解决方案2】:

    这似乎行得通。

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

    【讨论】:

    • 如果原始类不可用,这将不起作用,这(我认为)破坏了对静态方法进行腌制和解封的目的-您允许对其进行腌制,但您需要整个班级解开它。
    • 尝试例如: import pickle class MyClass(object): @PickleableStaticMethod def dosomething(a, b): print a, b pickled = pickle.dumps(MyClass.dosomething) del MyClass stm = pickle .loads(腌制)
    • 我想我可能只是在那里说了一些完全错误的话,pickle 与我预期的功能完全不同。忽略我最近的两个 cmets :-/
    • 嗨杰森。你能解释一下两件事吗:1)为什么应该有 get 方法 - 我认为可以避免 2)我认为如果 cls=None 在 unpickling 时它将不起作用
    猜你喜欢
    • 1970-01-01
    • 2011-02-25
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多