如何正确地pickle一个namedtuple实例

时间:2013-05-04 17:46:07

标签: python python-2.7 pickle namedtuple

我正在学习如何使用泡菜。我创建了一个namedtuple对象,将其附加到列表中,并试图挑选该列表。但是,我收到以下错误:

pickle.PicklingError: Can't pickle <class '__main__.P'>: it's not found as __main__.P

我发现如果我运行代码而不将其包装在函数中,它就可以完美地运行。在函数内部包装时,是否需要额外的步骤来腌制对象?

这是我的代码:

from collections import namedtuple
import pickle

def pickle_test():
    P = namedtuple("P", "one two three four")
    my_list = []
    abe = P("abraham", "lincoln", "vampire", "hunter")
    my_list.append(abe)
    f = open('abe.pickle', 'w')
    pickle.dump(abe, f)
    f.close()

pickle_test()

5 个答案:

答案 0 :(得分:64)

在函数

之外创建之外的命名元组
from collections import namedtuple
import pickle

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

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

pickle_test()

现在pickle可以找到它;它现在是一个全球模块。取消排版时,pickle模块所要做的就是再次找到__main__.P。在您的版本中,P本地,属于pickle_test()函数,并且不可内省或可导入。

重要的是要记住namedtuple()是一个班级工厂;你给它参数,它返回一个类对象,你可以从中创建实例。 pickle仅存储实例中包含的数据,以及对原始类的字符串引用,以便再次重构实例。

答案 1 :(得分:8)

在我将问题添加为对主要答案的评论之后,我找到了一种方法来解决制作动态创建namedtuple pickle-able的问题。这在我的情况下是必需的,因为我只是在运行时(在数据库查询之后)计算出它的字段。

通过有效地将其移至namedtuple模块,我所做的只是 monkey patch __main__

def _CreateNamedOnMain(*args):
    import __main__
    namedtupleClass = collections.namedtuple(*args)
    setattr(__main__, namedtupleClass.__name__, namedtupleClass)
    namedtupleClass.__module__ = "__main__"
    return namedtupleClass

请注意,如果您不小心,namedtuple名称(由args提供)可能会覆盖__main__中的其他成员。

答案 2 :(得分:3)

或者,您可以使用cloudpickledill进行序列化:

from collections import namedtuple

import cloudpickle
import dill



def dill_test(dynamic_names):
    P = namedtuple('P', dynamic_names)
    my_list = []
    abe = P("abraham", "lincoln", "vampire", "hunter")
    my_list.append(abe)
    with open('deleteme.cloudpickle', 'wb') as f:
        cloudpickle.dump(abe, f)
    with open('deleteme.dill', 'wb') as f:
        dill.dump(abe, f)


dill_test("one two three four")

答案 3 :(得分:3)

我在另一个帖子中找到了this answer。这就是命名元组的命名。这对我有用:

group_t =            namedtuple('group_t', 'field1, field2')  # this will work
mismatched_group_t = namedtuple('group_t', 'field1, field2')  # this will throw the error

答案 4 :(得分:0)

这里的问题是子进程无法导入对象的类 - 在这种情况下,类P-,在多模型项目的情况下,类P应该可以在子进程的任何地方导入习惯了

快速解决方法是通过将其影响为globals()

使其可导入
globals()["P"] = P