我正在尝试将动态生成的类作为替代类的工厂。如下所示:
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,因为我只需要它作为新类的工厂。
答案 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'>
>>>
在此处获取dill
:https://github.com/uqfoundation