酸洗动态生成的类?

时间:2012-07-25 20:57:51

标签: python class dynamic metaprogramming

我正在使用type()来动态生成最终会被腌制的类。问题是,un-pickling进程需要类的定义才能重新构造被pickle的对象。

这就是我被困住的地方。我不知道如何以某种方式提供 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)

6 个答案:

答案 0 :(得分:14)

当Pickler遇到一个它一无所知的类型的对象时,它会查找reduce method。使用类型构建自定义类时定义此方法应解决酸洗问题。

如果您提供初始参数,那么您可能需要定义getnewargs method

答案 1 :(得分:2)

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

  1. 动态类的名称
  2. 子类元组(可能是来自repr()的字符串形式)
  3. 班级词典
  4. 实际实例
  5. 这将允许你挑选一个类,然后使用type()和子类化Unpickler重新构建它。

答案 2 :(得分:1)

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

正如原帖中所提到的,这里的问题是对于动态类,默认的pickler不会对类定义本身进行pickle。由于模块的源文件中不存在动态类,因此通常无法对动态类进行取消操作。

挑选类本身最棘手的部分是存储方法的字节码。在PiCloud中埋葬,引擎盖下有一个增强的拾取器,可以pickle dynamic functions你可以使用或扩展它以处理你的物体。

答案 3 :(得分:1)

您可以为动态生成的类指定一个全局名称,以使其可以选择。

>>> 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)

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

答案 4 :(得分:0)

我自己从未这样做过,但是http://docs.python.org/library/pickle.html#subclassing-unpicklers似乎表明您可以通过继承Unpickler

来覆盖行为

答案 5 :(得分:0)

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

import cloudpickle

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