我有一个路易吉管道。我们有很多定期更改的外部文件,我们希望能够从元数据构建管道。
我动态创建类,并找到了两种方法:
使用执行:
exec("""
class {system}(DeliverySystem):
pass
""".format(system='ClassUsingExec'))
使用类型:
name = 'ClassUsingType'
globals()[name] = type(name, (DeliverySystem,),{})
这两种方法在单线程环境中都可以正常工作,但是当我开始运行 luigi 并且有许多工作人员产生子进程时,exec 版本很好,但是类型版本给出了本文和这篇文章中描述的错误(请参阅它们以获得更完整的堆栈痕迹):
PicklingError: Can't pickle <class 'abc.ClassUsingType'>: attribute lookup abc.ClassUsingType failed.
我可以在两者之间找到的唯一区别是模块:
print(ClassUsingExec.__dict__) #=>
mappingproxy({'__module__': '__main__',
'__doc__': None,
'__abstractmethods__': frozenset(),
'_abc_impl': <_abc_data at 0x15b5063c120>,
'_namespace_at_class_time': ''})
print(ClassUsingType.__dict__) #=>
mappingproxy({'__module__': 'abc',
'__doc__': None,
'__abstractmethods__': frozenset(),
'_abc_impl': <_abc_data at 0x15b3f870450>,
'_namespace_at_class_time': ''})
似乎模块不同,这可能是差异的来源。
使用 Python 3.6、Windows 10、luigi 2.8.9。
问题:
有没有办法用来type
创建一个类,以便它的模块是定义它的模块,而不是在abc
?
这些方法之间是否还有其他一些区别?根据这篇文章,应该没有区别,但我发现情况并非如此。