34

type()用来动态生成最终将被腌制的类。问题是取消腌制过程需要类的定义才能重新构造已腌制的对象。

这就是我卡住的地方。我不知道如何以某种方式unpickler 提供一种从动态生成的类生成实例的方法。

任何提示表示赞赏。

谢谢!

这是问题的一个例子:

    >>> class Foo(object):
    ...     pass
    >>> g=type('Goo',(Foo,),{'run':lambda self,x: 2*x } )()
    >>> cPickle.dumps(g)

    PicklingError: Can't pickle <class '__main__.Goo'>: attribute lookup __main__.Goo failed

这显然有效,但仅适用于从可腌制基类(具有可查找模块定义)创建的动态类:

import cPickle

class Foo(object): pass

def dynamic(): return type('Goo',(Foo,),{'run':lambda self,x: 2*x } )()

g=type('Goo',(Foo,),{'run':lambda self,x: 2*x , '__reduce__': lambda self: (dynamic,tuple()) } )()

gg=cPickle.loads ( cPickle.dumps(g) )
print gg.run(10)
4

6 回答 6

18

当 Pickler 遇到一个它不知道的类型的对象时,它会寻找reduce 方法。在使用 type 构建自定义类时定义此方法应该可以解决酸洗问题。

如果您提供初始参数,那么您可能还需要定义一个getnewargs 方法

于 2012-08-02T03:11:10.590 回答
5

您可以为动态生成的类分配一个全局名称以使其可挑选。

>>> class Foo(object):
...     pass
>>> class_name = 'Goo'
>>> my_class = type(class_name, (Foo, ), {'run': lambda self, x: 2*x })
>>> globals()[class_name] = my_class
>>> g = my_class()
>>> pickle.dumps(g)

当然,您需要确保类的名称是唯一的。

于 2016-09-16T10:24:30.217 回答
2

一个想法是用以下方法腌制一个元组:

  1. 动态类的名称
  2. 子类元组(可能是来自 repr() 的字符串形式)
  3. 类词典
  4. 实际实例

这将允许您腌制一个类,然后稍后使用 type() 和子类 Unpickler 重建它。

于 2012-07-25T21:06:59.393 回答
1

对于非动态类,python 的酸洗机制将模块和类名记录为字符串。在 unpickle 时,它​​会自动从该模块加载类对象。

正如原帖中提到的,这里的问题是,对于动态类,类定义本身并没有被默认的pickler腌制。由于模块的源文件中不存在动态类,因此取消动态类通常不起作用。

腌制类本身最棘手的部分是存储方法的字节码。隐藏在 PiCloud 中,引擎盖下有一个增强的pickler,可以pickle您可能使用或扩展它来处理您的对象的动态函数。

于 2012-08-02T12:54:13.650 回答
0

我自己从未做过,但http://docs.python.org/library/pickle.html#subclassing-unpicklers似乎表明您可以通过子类化来覆盖行为Unpickler

于 2012-07-25T21:04:50.280 回答
0

好吧,为了后代;与 cloudpickle 一起使用

import cloudpickle

class Foo(object):
    pass
g=type('Goo',(Foo,),{'run':lambda self,x: 2*x } )()
cloudpickle.dumps(g)
于 2020-03-11T07:51:57.493 回答