理解Python中NamedTupleTypeName和pickle的问题

理解Python中NamedTupleTypeName和pickle的问题,python,python-2.7,serialization,pickle,namedtuple,Python,Python 2.7,Serialization,Pickle,Namedtuple,今天早些时候,我在处理一个实例时遇到了困难。作为一种理智的检查,我试着运行一些发布的代码。在这里,简化了一点: 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',

今天早些时候,我在处理一个实例时遇到了困难。作为一种理智的检查,我试着运行一些发布的代码。在这里,简化了一点:

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
所以我的问题是到底发生了什么?为什么
typename
参数需要与工厂名称匹配才能工作?

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

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

可以通过查看问题的一个解决方法来说明这一点,即更改代码的一行,以便在顶层定义名为
my_typename
的类型:

P = my_typename = namedtuple("my_typename", "A B C")
或者,您可以只给
namedtuple
名称
“p”
,而不是
“我的类型名”

至于您正在查看的
namedtuple.py
源代码做了什么:它试图确定调用者(namedtuple的创建者)模块的名称是因为作者知道,
pickle
可能会尝试使用它来导入定义以进行取消勾选,并且人们通常会将结果分配给变量,其名称与传递给工厂函数的名称相同(但在第二个示例中您没有这样做)。

感谢您的“替代”方式。工作起来很有魅力。
P = my_typename = namedtuple("my_typename", "A B C")
P = namedtuple("P", "A B C")