Python 动态类定义的pickle

Python 动态类定义的pickle,python,pickle,dynamic-class,Python,Pickle,Dynamic Class,我试图将动态生成的类作为替代类的工厂进行pickle。如下所示: import sys, pickle class BC(object): pass C = type("NewClassName", (BC,), {}) pickle.dump(C, sys.stdout) C = type("C", (BC,), {}) 这会导致以下错误: pickle.PicklingError: Can't pickle <class '__main__.NewClassName'

我试图将动态生成的类作为替代类的工厂进行pickle。如下所示:

import sys, pickle

class BC(object):
    pass

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

pickle.dump(C, sys.stdout)
C = type("C", (BC,), {})
这会导致以下错误:

pickle.PicklingError: Can't pickle <class '__main__.NewClassName'>: it's not found as __main__.NewClassName
pickle.PicklingError:无法pickle:找不到它作为\uuuuu main\uuuuuuu.NewClassName
对于动态生成的类的pickle对象,您可以定义
\uuuuu reduce\uuuuu
方法,但是否有一种方法仅用于类定义

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

尝试以下操作:

import sys, pickle

class BC(object):
    pass

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

pickle.dump(C, sys.stdout)
C = type("C", (BC,), {})
该类必须是模块级变量,与类型名同名

但是,像这样对动态生成的类进行pickle将不起作用(请参见@otus的答案)


我能想到的最好的解决方案是将参数pickle到
type
,然后在取消pickle时重新创建该类

泡菜:

import sys, pickle

class BC(object):
    pass

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

pickle.dump(C._pickle_args, sys.stdout)
解钩:

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

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

import sys, pickle

class BC(object):
    pass

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

pickle.dump(NewClassName, sys.stdout)
再次出现错误:

AttributeError: 'module' object has no attribute 'NewClassName'
除非您已经定义了类


作为缔约国:

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

所以你不能用它来生成新的类,只是为了确保你的对象引用了正确的类


有一些解决方法,如pickling
type
参数,如中所示,但即使如此,如果不在pickling和取消pickling过程的全局命名空间中公开该类,您也无法对这些动态类的对象进行pickle(即
\uu main\uu.ClassName
必须引用该类)


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

您可以使用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'>
>>> 
Python 2.7.7(默认,2014年6月2日01:33:50)
达尔文的[GCC 4.2.1兼容Apple Clang 4.1((tags/Apple/Clang-421.11.66))]
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
>>>进口莳萝
>>>>
>>>BC类(对象):
…通过
... 
>>>c=type(“NewClassName”,(BC,),{})
>>>_c=dill.dumps(c)
>>>c2=静载荷(_c)
>>>c2
>>> 

获取
dill
此处:

为什么要对动态生成的类进行pickle处理?难道不能简单地序列化用于创建该类的参数,然后在其他地方重新创建它吗?我的意思是,对类进行pickle处理是元编程,这有点太过分了。我想不出一个真实的示例。现在没有变量
C
可供选择le应该是:
pickle.dump(NewClassName,sys.stdout)
@JamieCockburn,实际上是打字错误。无论如何,这“解决”了错误,但可能不是用户想要完成的。谢谢你的快速回复!问题是,C是一个固定变量名,不能根据“NewClassName”进行更改@eatdas,请参阅我对答案的更新。如果您试图加载“当前”中不存在的动态生成的类声明,
pickle
单独对您不起作用。@otus您是对的,这说明pickle类定义没有引用类的基。只是没有保存重新创建类定义的信息。