Python 如何正确地pickle namedtuple实例
我正在学习如何使用泡菜。我创建了一个namedtuple对象,将其附加到列表中,并尝试对该列表进行pickle。但是,我得到以下错误:Python 如何正确地pickle namedtuple实例,python,python-2.7,pickle,namedtuple,Python,Python 2.7,Pickle,Namedtuple,我正在学习如何使用泡菜。我创建了一个namedtuple对象,将其附加到列表中,并尝试对该列表进行pickle。但是,我得到以下错误: pickle.PicklingError: Can't pickle <class '__main__.P'>: it's not found as __main__.P 在函数外部创建命名元组: from collections import namedtuple import pickle P = namedtuple("P", "one t
pickle.PicklingError: Can't pickle <class '__main__.P'>: it's not found as __main__.P
在函数外部创建命名元组:
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
模块需要做的就是再次定位\uuuu main\uuu.P
。在您的版本中,P
是pickle\u test()
函数的本地函数,它不可内省或导入
重要的是要记住,
namedtuple()
是一个类工厂;您为它提供参数,它将返回一个类对象,供您从中创建实例<代码>pickle只存储实例中包含的数据,加上对原始类的字符串引用以再次重构实例。在我将问题作为注释添加到主要答案后,我找到了一种方法来解决动态创建的namedtuple
pickle的问题。这在我的例子中是必需的,因为我只在运行时(在DB查询之后)计算它的字段
我所做的就是通过有效地将\uuuu主模块
移动到模块,对命名双工
进行猴子补丁:
def _CreateNamedOnMain(*args):
import __main__
namedtupleClass = collections.namedtuple(*args)
setattr(__main__, namedtupleClass.__name__, namedtupleClass)
namedtupleClass.__module__ = "__main__"
return namedtupleClass
请注意,如果您不小心,namedtuple
名称(由args
提供)可能会覆盖\uuuuu main\uuuu
中的另一个成员。或者,您可以使用或进行序列化:
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")
我在另一个线程中发现。这都是关于命名元组的命名。这对我很有用:
group_t = namedtuple('group_t', 'field1, field2') # this will work
mismatched_group_t = namedtuple('group_t', 'field1, field2') # this will throw the error
这里的问题是,子进程无法导入对象的类(在本例中为类p),在多模型项目中,类p应该可以在子进程使用的任何位置导入
一个快速的解决方法是通过将其影响到globals()使其可导入
不幸的是,pickle似乎不能很好地处理namedtuple。@锑:pickle
可以很好地处理namedtuple类;在函数本地名称空间中定义的类不多。可能与@AirThomas重复此问题是在一年前提出/回答的:)无需回答。我只是觉得很有趣。问题链接确实非常有用:)那么,如果我动态创建namedtuple
,因为我直到运行时才知道字段,该怎么办?还有办法绕过这个问题吗?我尝试在类之外创建另一个方法,但没有成功。@Chuim:将其分配给同名的模块全局(使用globals()
获取映射),并且pickle
仍然可以找到它。如果您正在创建带动态字段的多个namedtuple,在覆盖globals
@DavitTovmasyan中的P
后,取消勾选将不起作用:不,每个类都需要一个单独的名称。只需将其设置为globals()
即可:globals()[namedtupleClass.\uu name\uuuu]=namedtupleClass
。当我尝试globals()[namedtupleClass.\uu name\uuu]=namedtupleClass
时,它确实允许我对对象进行pickle,但当我尝试取消pickle时,它没有所需的namedtupleClass
。我的建议是使用字典,直到他们把pickle弄得足够聪明,可以这样做。
group_t = namedtuple('group_t', 'field1, field2') # this will work
mismatched_group_t = namedtuple('group_t', 'field1, field2') # this will throw the error
globals()["P"] = P