【问题标题】:Pickling dynamically generated classes?酸洗动态生成的类?
【发布时间】:2012-07-24 09:40:14
【问题描述】:

我正在使用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)

【问题讨论】:

  • 避免使用pickle...它很慢,很脆弱,并且可以打开任意代码执行漏洞。相反,请使用 JSON 或 YAML 等序列化格式。
  • 您能否提供您动态创建的类的示例代码?
  • @ColinDunklau 我认为如果您使用 python 的多处理模块和共享内存,那么您必须确保您共享的对象可以被腌制。 mp 模块使用酸洗来实现共享内存。

标签: python class dynamic metaprogramming pickle


【解决方案1】:

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

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

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 它在 cloud.serialization.cloudpickle
      • 还有一个名为dill的包,它也可以pickle动态创建的类和类实例。这是一个非常小的包,可以序列化大多数python对象。
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          猜你喜欢
          • 2014-08-13
          • 2021-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多