下面的python代码失败,错误为pickle.PicklingError: Can't pickle <class '__main__.SpecialName'>: it's not found as __main__.SpecialName
import pickle
from collections import namedtuple
different_SpecialName = namedtuple('SpecialName', 'foo bar')
def save():
foo = different_SpecialName(1, 2)
with open('foosave.pkl', 'w') as f:
pickle.dump(foo, f)
if __name__ == '__main__':
save()
这似乎是pickle
模块的不良行为,因为它取决于变量名称的正确性。将different_SpecialName
更改为SpecialName
并重新运行代码可以使其成功完成。将代码更改为下面,其中SpecialName
的变量被实例化为与different_SpecialName
相同的值,也可以让代码成功运行
import pickle
from collections import namedtuple
different_SpecialName = namedtuple('SpecialName', 'foo bar')
## create new variable with 'correct' name
SpecialName = different_SpecialName
def save():
# foo = different_SpecialName(1, 2)
foo = SpecialName(1, 2)
with open('foosave.pkl', 'w') as f:
pickle.dump(foo, f)
if __name__ == '__main__':
save()
我的问题:这基本上是pickle
(和cPickle
)错误吗?似乎pickle
不应该通过使用变量的名称来查找类定义(尽管我不确定它还能做什么)。或者,这是namedtuple
API的问题吗?我浏览了namedtuple
documentation并且无法找到任何明确告诉我将namedtuple
变量命名为typename
参数的内容(namedtuple()
的第一个参数功能)
答案 0 :(得分:1)
这不是一个错误。 pickle
requires
类定义必须是可导入的,并且与存储对象时存在于同一模块中。
从namedtuple
的{{1}}方法的角度来看,类型名称是__reduce__
(这就是你传递给它的东西)。因此,当unpickling时,它将尝试导入声明它的模块并查找SpecialName
。但由于您没有将其保存为SpecialName
,因此无法找到它。
如果不诉诸SpecialName
,您可以通过以下方式产生完全相同的问题:
namedtuple
并尝试挑剔和取消class Foo:
pass
Bar = Foo
del Foo
;在引擎盖下,您使用Bar()
的不匹配名称有效地完成了同样的事情。