酸洗动态类定义

时间:2014-06-23 11:10:17

标签: python pickle dynamic-class

我正在尝试将动态生成的类作为替代类的工厂。如下所示:

import sys, pickle

class BC(object):
    pass

C = type("NewClassName", (BC,), {})

pickle.dump(C, sys.stdout)

这会导致以下错误:

pickle.PicklingError: Can't pickle <class '__main__.NewClassName'>: it's not found as __main__.NewClassName

对于动态生成的类的对象进行pickle,您可以定义__reduce__方法,但是有一种方法可以仅为类定义实现此方法。

我不想直接使用BC,因为我只需要它作为新类的工厂。

3 个答案:

答案 0 :(得分:2)

尝试以下方法:

C = type("C", (BC,), {})

该类必须是模块级变量,其名称与类型名称相同。

然而,像这样挑选一个动态生成类的类是行不通的(参见@otus的答案)。


我能想到的最好的解决方案是挑选type的参数,然后在你取消它时再次重新创建该类。

味酸:

import sys, pickle

class BC(object):
    pass

args = ("NewClassName", (BC,), {})
C = type(*args)
C._pickle_args = args

pickle.dump(C._pickle_args, sys.stdout)

Unpickle:

type_args = pickle.loads("<pickled string">)
C = type(*args)

答案 1 :(得分:2)

错误的一个简单解决方法是使用类名作为变量名,以便pickle可以找到它:

import sys, pickle

class BC(object):
    pass

NewClassName = type("NewClassName", (BC,), {})

pickle.dump(NewClassName, sys.stdout)

然而,这可能并不是真正做你想要的。加载酸洗类时:

pickle.loads("""c__main__
NewClassName
p0
.""")

您再次收到错误:

AttributeError: 'module' object has no attribute 'NewClassName'

除非您已经定义了该课程。


正如documentation所述:

  

pickle可以透明地保存和恢复类实例,但是类定义必须是可导入的,并且与存储对象时存在于同一个模块中。

因此,您无法使用它来生成新类,只是为了确保您的对象引用正确的类。


other answer中显示了诸如腌制type参数之类的解决方法,但即使这样,您也无法在不暴露类的情况下挑选这些动态类的对象在pickling和unpickling过程的全局命名空间中(即__main__.ClassName必须引用该类)。

因此,我会重新思考整个动态类方法。

答案 2 :(得分:1)

您可以使用dill,它可以序列化动态类定义。那么你不需要任何解决方法,你可以做你想做的事。

Python 2.7.7 (default, Jun  2 2014, 01:33:50) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>>>
>>> class BC(object):
...   pass
... 
>>> c = type("NewClassName", (BC,), {})
>>> _c = dill.dumps(c)    
>>> c2 = dill.loads(_c)
>>> c2
<class '__main__.NewClassName'>
>>> 

在此处获取dillhttps://github.com/uqfoundation