【问题标题】:Python: Can't pickle type X, attribute lookup failedPython:无法腌制类型 X,属性查找失败
【发布时间】:2011-06-08 07:12:49
【问题描述】:

我正在尝试腌制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 的定义移到顶层可以解决问题,尽管我仍然很好奇为什么会发生这种情况。)

【问题讨论】:

  • 使用 python3 和 pickle 协议 4 解决了这个问题
  • @DaveButler 的回答是否正确?谁能确认或否认?

标签: python pickle


【解决方案1】:

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

>>> 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()返回一个类型对象时,它并不知道它被分配给一个类成员的事实——因此,它告诉类型对象它的类型名称应该是__main__.Bar ,即使它确实应该是__main__.Foo.Bar

【讨论】:

  • namedtuple 只是不适合类。您也许可以为将手动处理它的对象编写自定义 __getstate__
  • 早期绑定会抓住那个吗?
  • 我如何使用 getstate?我不知道如何实现。目前我正在使用一个临时解决方案,将命名元组列表传输到字典。
【解决方案2】:

嵌套类会使 pickle 失败,因为它依赖于应用程序内部对象的路径来稍后重建它。

直接的解决方案是不嵌套类,即将Bar 定义移到Foo 之外。代码将完全一样。

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

您刚刚遇到了 pickle 的诸多不便之一,如果您更改代码、移动内容或有时进行小的结构更改,您的数据将变得无法加载。

除此之外,pickle 还有其他缺点:速度慢、不安全、仅限 python...

【讨论】:

    【解决方案3】:

    在这里使用莳萝代替泡菜可以实现这一点

    【讨论】:

    • import dill; dill.dumps(x)
    • 这对我也不起作用。我得到:不能腌制 :它不是 main.RoadAttributesPartition
    【解决方案4】:

    这里的解决方案是将您的命名元组定义移动到模块级别,然后 pickle 工作。这里提供了详细的答案:

    How to pickle a namedtuple instance correctly

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 2018-07-14
      • 1970-01-01
      • 2016-03-15
      • 1970-01-01
      • 2017-11-23
      相关资源
      最近更新 更多