我的代码当前结构如下。
在script1.py
中,我有以下内容:
def func():
class MyClass():
pass
return MyClass
在script2.py
中,我有以下内容:
import script1
import pickle
the_class = script1.func()
f = open(FILE_PATH, "wb")
pickle.dump(the_class, f)
f.close()
但是,script2.py
给出了错误:
AttributeError: Can't pickle local object 'func.<locals>.MyClass'
问题1:为什么会发生这种情况?我该如何解决?
问题2:我可以重组代码以更简洁的方式获得相同的结果吗?我希望类的定义出现在单独的模块中。将类“引入”主脚本后,我想保存它。
谢谢!
答案 0 :(得分:0)
要回答问题1:之所以发生这种情况,是因为每次调用该函数都将创建一个新类。因此,该类在模块级别是未知的。据我所记得,这是泡菜的要求。而且我没有解决此问题的方法。
要解决第二个问题,最好知道为什么为什么。您想解决什么问题?这可能有助于指导解决方案。
答案 1 :(得分:0)
我是dill
的作者。我不确定您为什么说dill
不能帮助您。
首先,如果我们尝试序列化您的类,那么它可以工作:
>>> def func():
... class MyClass():
... pass
... return MyClass
...
>>> import dill
>>> c = func()
>>> c
<class '__main__.func.<locals>.MyClass'>
>>>
>>> dill.dumps(c)
b'\x80\x03cdill._dill\n_create_type\nq\x00(cdill._dill\n_load_type\nq\x01X\x04\x00\x00\x00typeq\x02\x85q\x03Rq\x04X\x07\x00\x00\x00MyClassq\x05h\x01X\x06\x00\x00\x00objectq\x06\x85q\x07Rq\x08\x85q\t}q\n(X\n\x00\x00\x00__module__q\x0bX\x08\x00\x00\x00__main__q\x0cX\x07\x00\x00\x00__doc__q\rNutq\x0eRq\x0f.'
>>> c_ = dill.loads(_)
>>> c_
<class '__main__.MyClass'>
>>>
因此,由于我们知道该类已序列化,因此我们可以从您的模块中获取它……尽管这就是问题……如果您尝试序列化未安装模块中定义的任何内容(即,仅从从当前目录导入的脚本),则由于序列化程序无法找到本地定义的模块(除非位于__main__
中),该脚本应该会失败。问题在于模块...如果出于任何原因而反对安装模块...则必须诉诸dill
鲜为人知的功能,即从对象中获取源代码。如下所示,您可以抓取该类并在本地定义它,也可以抓取该函数并在本地定义它。然后它将序列化:
>>> import dill
>>> import script1
>>> exec(dill.source.getsource(script1.func(), lstrip=True))
>>> MyClass
<class '__main__.MyClass'>
>>> # or...
>>> exec(dill.source.getsource(script1.func))
>>> c = func()
>>>
>>> dill.dumps(c)
b'\x80\x03cdill._dill\n_create_type\nq\x00(cdill._dill\n_load_type\nq\x01X\x04\x00\x00\x00typeq\x02\x85q\x03Rq\x04X\x07\x00\x00\x00MyClassq\x05h\x01X\x06\x00\x00\x00objectq\x06\x85q\x07Rq\x08\x85q\t}q\n(X\n\x00\x00\x00__module__q\x0bX\x08\x00\x00\x00__main__q\x0cX\x07\x00\x00\x00__doc__q\rNutq\x0eRq\x0f.'
>>> dill.loads(_)
<class '__main__.MyClass'>
>>>
要做的是 not 尝试从未安装的模块进行序列化。要么安装要从中导入的模块,要么将生成类的函数放在与转储该类的脚本相同的文件中。