【问题标题】:Is it possible to decorate a Python class whose instances will be pickled?是否可以装饰其实例将被腌制的 Python 类?
【发布时间】:2013-01-24 17:23:55
【问题描述】:

以下代码运行正确:

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)

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

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

怎么了?

【问题讨论】:

  • 呃,这个装饰器的问题不止于此。它只是不是一个类,它已成为一个工厂函数。例如,您不能使用它键入检查或子类化它。

标签: python decorator pickle python-decorators


【解决方案1】:

Pickle 必须能够直接加载类。您的装饰器替换类与工厂函数,使泡菜无法导入类本身。

使用单独的工厂函数,而不是装饰器,返回一个“私有”类(但仍可直接导入):

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]

【讨论】:

【解决方案2】:

为此,我会使用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,可帮助您了解在代码失败时导致酸洗失败的原因。

【讨论】:

    猜你喜欢
    • 2017-02-22
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 2016-01-05
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    相关资源
    最近更新 更多