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

Nic*_*ner 42 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()
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

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
Run Code Online (Sandbox Code Playgroud)

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

Amb*_*ber 30

是的,它是一个类成员的事实是一个问题:

>>> 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'>
Run Code Online (Sandbox Code Playgroud)

问题是当namedtuple()返回一个类型对象时,它不知道它被分配给一个类成员 - 因此,它告诉类型对象它的类型名称应该是__main__.Bar,即使它应该是真的__main__.Foo.Bar.

  • 那么......是否有一些解决方法,或者只是被禁止? (7认同)
  • `namedtuple` 只是不适合类。您可以为对象编写一个自定义的 `__getstate__` 来手动处理它。 (2认同)

nos*_*klo 13

嵌套类使得pickle失败,因为它依赖于应用程序内部对象的路径以便以后重构它.

直接的解决方案是不嵌套类,即将Bar定义移到外部Foo.代码将完全相同.

但更好的办法是根本不用 pickle来存储数据.使用一些其他序列化格式,如json,或数据库,如sqlite3.

你刚刚遇到了很多不便之处,如果你改变代码,移动东西,或者有时进行小的结构改变,你的数据就会变得无法加载.

除此之外,泡菜还有其他缺点:它很慢,不安全,只有python ......


Max*_*ian 7

在这里用莳萝代替泡菜可以使它工作

  • `进口莳萝;dill.dumps(x)` (4认同)