Python:无法腌制类型 X,属性查找失败
Posted
技术标签:
【中文标题】Python:无法腌制类型 X,属性查找失败【英文标题】:Python: Can't pickle type X, attribute lookup failed 【发布时间】: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
我做错了什么?问题是Bar
是Foo
的成员吗? (将Bar
的定义移到顶层可以解决问题,尽管我仍然很好奇为什么会发生这种情况。)
【问题讨论】:
使用 python3 和 pickle 协议 4 解决了这个问题 @DaveButler 的回答是否正确?谁能确认或否认? 【参考方案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)
这对我也不起作用。我得到:不能腌制 这里的解决方案是将您的命名元组定义移动到模块级别,然后 pickle 工作。这里提供了详细的答案:
How to pickle a namedtuple instance correctly
【讨论】:
以上是关于Python:无法腌制类型 X,属性查找失败的主要内容,如果未能解决你的问题,请参考以下文章
构建 Python 扩展失败(“kernel32.lib”无法打开 |“x64”与目标机器类型“x86”冲突)
在 Kotlin 中无法“findViewById”。收到错误“类型推断失败”