我正在尝试挑选namedtuple
:
from collections import namedtuple
import cPickle
class Foo:
Bar = namedtuple('Bar', ['x', 'y'])
def baz(self):
s = set()
s.add(Foo.Bar(x=2, y=3))
print cPickle.dumps(s)
if __name__ == '__main__':
f = Foo()
f.baz()
这会产生以下输出:
Traceback (most recent call last):
File "scratch.py", line 15, in <module>
f.baz()
File "scratch.py", line 11, in baz
print cPickle.dumps(s)
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed
我做错了什么?问题是Bar
是Foo
的成员吗? (将Bar
的定义移到顶层可以解决问题,尽管我仍然很好奇为什么会发生这种情况。)
答案 0 :(得分:28)
是的,它是一个类成员的事实是一个问题:
>>> class Foo():
... Bar = namedtuple('Bar', ['x','y'])
... def baz(self):
... b = Foo.Bar(x=2, y=3)
... print(type(b))
...
>>> a = Foo()
>>> a.baz()
<class '__main__.Bar'>
问题是当namedtuple()
返回一个类型对象时,它不知道它被分配给一个类成员 - 因此,它告诉类型对象它的类型名称应该是{ {1}},即使它应该是__main__.Bar
。
答案 1 :(得分:13)
嵌套类使pickle失败,因为它依赖于应用程序内部对象的路径以便以后重构它。
立即解决方案是不嵌套类,即将Bar
定义移到外部Foo
。代码将完全相同。
但更好的办法是根本不使用 pickle
来存储数据。使用其他序列化格式(如json
)或数据库(如sqlite3
。
你刚刚遇到了很多不便之处,如果你改变代码,移动东西,或者有时进行小的结构改变,你的数据就会变得无法加载。
除此之外,pickle还有其他缺点:它很慢,不安全,只有python ......
答案 2 :(得分:6)
在这里使用莳萝代替泡菜将使这个工作
答案 3 :(得分:0)
这里的解决方案是将命名的元组定义移至模块级别,然后进行pickle。这里提供了详细的答案: