使用namedtuple的多进程对象 - Pickling错误
我在使用命名元组(namedtuples)时遇到了麻烦,特别是在我想把它们放到多进程(multiprocessing)中使用的时候。我收到了一个关于序列化(pickling)的错误。我尝试了从其他StackOverflow帖子上找到的一些方法,但都没有成功。以下是我代码的结构:
package_main, test_module
import myprogram.package_of_classes.data_object_module
import ....obj_calculate
class test(object):
if __name__ == '__main__':
my_obj=create_obj('myobject',['f1','f2'])
input = multiprocessing.Queue()
output = multiprocessing.Queue()
input.put(my_obj)
j=Process(target=obj_calculate, args=(input,output))
j.start()
package_of_classes, data_object_module
import collections
import ....load_flat_file
def get_ntuple_format(obj):
nt_fields=''
for fld in obj.fields:
nt_fields=nt_fields+fld+', '
nt_fields=nt_fields[0:-2]
ntuple=collections.namedtuple('ntuple_format',nt_fields)
return ntuple
Class Data_obj:
def __init__(self, name,fields):
self.name=name
self.fields=fields
self.ntuple_form=get_ntuple_format(self)
def calculate(self):
self.file_read('C:/files','division.txt')
def file_read(self,data_directory,filename):
output=load_flat_file(data_directory,filename,self.ntuple_form)
self.data=output
utils_package, utils_module
def create_dataobj(name,fields):
locals()[name]=Data_Obj(name,fields)
return locals()[name]
def obj_calculate(input,output):
obj=input.get()
obj.calculate()
output.put(obj)
loads_module
def load_flat_file(data_directory,filename,ntuple_form):
csv.register_dialect('csvrd', delimiter='\t', quoting=csv.QUOTE_NONE)
ListofTuples=[]
with open(os.path.join(data_directory,filename), 'rb') as f:
reader = csv.reader(f,'csvrd')
for line in reader:
if line:
ListofTuples.append(ntuple_form._make(line))
return ListofTuples
我遇到的错误是:
PicklingError: PicklingError: Can't pickle class '__main__ . ntuple_format: it's not the same object as __ main __. ntuple_format
附注:因为我从一个大项目中提取了这段示例代码,所以请忽略一些小的不一致之处。
2 个回答
3
我认为你可以对一个 namedtuple
进行序列化,就像对一个在 __main__
中定义的 class
一样。
>>> import dill as pickle
>>> import collections
>>>
>>> thing = collections.namedtuple('thing', ['a','b'])
>>> pickle.loads(pickle.dumps(thing))
<class '__main__.thing'>
这里是同样的内容,放在一个类的方法里使用。
>>> class Foo(object):
... def bar(self, a, b):
... thing = collections.namedtuple('thing', ['a','b'])
... thing.a = a
... thing.b = b
... return thing
...
>>> f = Foo()
>>> q = f.bar(1,2)
>>> q.a
1
>>> q.b
2
>>> q._fields
('a', 'b')
>>>
>>> pickle.loads(pickle.dumps(Foo.bar))
<unbound method Foo.bar>
>>> pickle.loads(pickle.dumps(f.bar))
<bound method Foo.bar of <__main__.Foo object at 0x10dbf5450>>
你只需要用 dill
代替 pickle
就可以了。
你可以在这里获取 dill
: https://github.com/uqfoundation
7
你不能对动态创建的类(在这里指的是命名元组)进行序列化(也就是“腌制”)。为了让一个类可以被序列化,它必须在一个可以被导入的模块的最顶层定义。
如果你只需要支持几种元组,可以考虑提前在模块的最顶层定义好它们,然后在需要的时候动态选择合适的。如果你需要一个完全动态的容器格式,可以考虑直接使用一个 dict
(字典)。