Python:不能腌制类型X,属性查找失败

时间:2011-01-13 05:14:05

标签: python pickle

我正在尝试挑选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

我做错了什么?问题是BarFoo的成员吗? (将Bar的定义移到顶层可以解决问题,尽管我仍然很好奇为什么会发生这种情况。)

4 个答案:

答案 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。这里提供了详细的答案:

How to pickle a namedtuple instance correctly