如何正确咸菜一个namedtuple实例(How to pickle a namedtuple in

2019-09-02 00:02发布

我正在学习如何使用咸菜。 我创建了一个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()

Answer 1:

创建功能之外的命名元组:

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只存储包含在所述实例中的数据 ,再加上一个字符串引用原始类再次重建实例。



Answer 2:

之后,我将我的问题,即主要答复评论我找到了一种方法来解决使动态创建的问题namedtuple咸菜,能。 这是需要在我的情况,因为我搞清楚它的领域仅在运行时(后DB查询)。

我要做的就是猴子修补 namedtuple通过有效地将其移动到__main__模块:

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

记住, namedtuple名称(这是由提供args )可能会覆盖另一个成员在__main__如果你不小心。



Answer 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")


Answer 4:

我发现这个答案在另一个线程。 这是所有关于命名元组的命名。 这为我工作:

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


Answer 5:

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

一个快速的解决方法是使其可导入由它影响到全局变量()

globals()["P"] = P


文章来源: How to pickle a namedtuple instance correctly