gpt4 book ai didi

python - 了解 Python 中 namedtuple typename 和 pickle 的问题

转载 作者:太空狗 更新时间:2023-10-29 22:26:37 24 4
gpt4 key购买 nike

今天早些时候,我在尝试 pickle namedtuple 时遇到了麻烦实例。作为完整性检查,我尝试运行一些已发布的代码 in another answer .在这里,再简化一点:

from collections import namedtuple
import pickle

P = namedtuple("P", "one two three four")

def pickle_test():
abe = P("abraham", "lincoln", "vampire", "hunter")
f = open('abe.pickle', 'w')
pickle.dump(abe, f)
f.close()

pickle_test()

然后我更改了其中的两行以使用我命名的元组:

from collections import namedtuple
import pickle

P = namedtuple("my_typename", "A B C")

def pickle_test():
abe = P("ONE", "TWO", "THREE")
f = open('abe.pickle', 'w')
pickle.dump(abe, f)
f.close()

pickle_test()

但是这给了我错误

  File "/path/to/anaconda/lib/python2.7/pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <class '__main__.my_typename'>: it's not found as __main__.my_typename

即Pickle 模块正在寻找 my_typename。我将 P = namedtuple("my_typename", "A B C") 行更改为 P = namedtuple("P", "A B C") 并且它起作用了。

我查看了 namedtuple.py 的源代码,最后我们有一些看起来相关的东西,但我不完全明白发生了什么:

# For pickling to work, the __module__ variable needs to be set to the frame
# where the named tuple is created. Bypass this step in enviroments where
# sys._getframe is not defined (Jython for example) or sys._getframe is not
# defined for arguments greater than 0 (IronPython).
try:
result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
except (AttributeError, ValueError):
pass

return result

所以我的问题是到底发生了什么?为什么 typename 参数需要匹配工厂的名称才能工作?

最佳答案

在标题为 What can be pickled and unpickled? 的部分中在 Python 文档中,它表示只能 pickle “在模块顶层定义的类”。然而namedtuple()是一个工厂函数,它有效地定义了一个类(my_typename(tuple) 在你的第二个例子中),但是它没有将制造的类型分配给名为 my_typename 的变量 在模块的顶层。

这是因为 pickle 只保存这些东西的“完全限定”名称,而不是它们的代码,并且它们必须能够从它们所在的模块中导入使用此名称是为了以后能够 unpickled(因此要求模块必须在顶层包含命名对象)。

这可以通过查看该问题的一种变通方法来说明——即更改一行代码,以便在顶部定义名为 my_typename 的类型级别:

P = my_typename = namedtuple("my_typename", "A B C")

或者,您可以只为 namedtuple 指定名称 "P" 而不是 "my_typename":

P = namedtuple("P", "A B C")

至于您正在查看的 namedtuple.py 源代码的作用:它试图确定调用者(namedtuple 的创建者)的模块名称因为作者知道 pickle 可能会尝试使用它来import 定义来进行 unpickling,而且人们通常将结果分配给与他们传递给的名称相同的变量工厂函数(但在第二个示例中没有)。

关于python - 了解 Python 中 namedtuple typename 和 pickle 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20143726/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com