当变量名称与typename

时间:2015-09-24 20:05:22

标签: python pickle namedtuple

下面的python代码失败,错误为pickle.PicklingError: Can't pickle <class '__main__.SpecialName'>: it's not found as __main__.SpecialName

import pickle
from collections import namedtuple

different_SpecialName = namedtuple('SpecialName', 'foo bar')
def save():
    foo = different_SpecialName(1, 2)
    with open('foosave.pkl', 'w') as f:
        pickle.dump(foo, f)

if __name__ == '__main__':
    save()

这似乎是pickle模块的不良行为,因为它取决于变量名称的正确性。将different_SpecialName更改为SpecialName并重新运行代码可以使其成功完成。将代码更改为下面,其中SpecialName的变量被实例化为与different_SpecialName相同的值,也可以让代码成功运行

import pickle
from collections import namedtuple

different_SpecialName = namedtuple('SpecialName', 'foo bar')

## create new variable with 'correct' name
SpecialName = different_SpecialName

def save():
    # foo = different_SpecialName(1, 2)
    foo = SpecialName(1, 2)
    with open('foosave.pkl', 'w') as f:
        pickle.dump(foo, f)

if __name__ == '__main__':
    save()

我的问题:这基本上是pickle(和cPickle)错误吗?似乎pickle不应该通过使用变量的名称来查找类定义(尽管我不确定它还能做什么)。或者,这是namedtuple API的问题吗?我浏览了namedtuple documentation并且无法找到任何明确告诉我将namedtuple变量命名为typename参数的内容(namedtuple()的第一个参数功能)

1 个答案:

答案 0 :(得分:1)

这不是一个错误。 pickle requires

  

类定义必须是可导入的,并且与存储对象时存在于同一模块中。

namedtuple的{​​{1}}方法的角度来看,类型名称是__reduce__(这就是你传递给它的东西)。因此,当unpickling时,它将尝试导入声明它的模块并查找SpecialName。但由于您没有将其保存为SpecialName,因此无法找到它。

如果不诉诸SpecialName,您可以通过以下方式产生完全相同的问题:

namedtuple

并尝试挑剔和取消class Foo: pass Bar = Foo del Foo ;在引擎盖下,您使用Bar()的不匹配名称有效地完成了同样的事情。