是否可以修饰其实例将被pickle的Python类?

时间:2013-01-24 17:23:56

标签: python decorator pickle python-decorators

以下代码正确运行:

import pickle

class MyClass():   
    def __init__(self, arg):
        self.arg = arg

a = MyClass('my arg')
with open('/home/mahikeulbody/mypickle', 'wb') as file:
    pickle.dump(a, file)

但是添加一个装饰器来获得一个多元类:

import pickle

def multiton(cls):
    instances = {}
    def getinstance(arg):
        if arg not in instances:
            instances[arg] = cls(arg)
        return instances[arg]
    return getinstance

@multiton
class MyClass():   
    def __init__(self, arg):
        self.arg = arg

a = MyClass('my arg')
with open('/home/michel/mypickle', 'wb') as file:
    pickle.dump(a, file)

产生以下错误:

pickle.dump(a, file)
_pickle.PicklingError: Can't pickle <class '__main__.MyClass'>: it's not the same object as __main__.MyClass

有什么问题?

2 个答案:

答案 0 :(得分:2)

Pickle必须能够直接加载该类。你的装饰者用工厂函数替换类,这使得pickle无法导入类本身。

使用单独的工厂功能,而不是装饰器,返回私人&#39; class(但仍可直接导入):

class _MyClass():   
    def __init__(self, arg):
        self.arg = arg

def MyClass(arg, instances={}):
    if arg not in instances:
        instances[arg] = _MyClass(arg)
    return instances[arg]

答案 1 :(得分:0)

为此,我使用dill,它可以在python中序列化几乎任何东西。

>>> def multiton(cls):
...     instances = {}
...     def getinstance(arg):
...         if arg not in instances:
...             instances[arg] = cls(arg)
...         return instances[arg]
...     return getinstance
... 
>>> @multiton
... class MyClass():   
...     def __init__(self, arg):
...         self.arg = arg
... 
>>> import dill
>>>                       
>>> a = MyClass('my arg')
>>> b = dill.loads(dill.dumps(a))
>>> a
<__main__.MyClass instance at 0x4d64558>
>>> b
<__main__.MyClass instance at 0x4d64800>

Dill还有some good tools帮助您了解代码失败时导致酸洗失败的原因。