在Python中动态创建类时exec vs type

2024-04-19 11:59:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一条路易吉管道。我们有很多经常变化的外部文件,我们希望能够从元数据构建管道。你知道吗

我动态创建类,并找到了两种方法:

使用exec:

exec("""
class {system}(DeliverySystem):
    pass
""".format(system='ClassUsingExec'))

使用类型:

name = 'ClassUsingType'
globals()[name] = type(name, (DeliverySystem,),{})

这两种方法在单线程环境中都可以很好地工作,但当我开始运行luigi时,许多工人都在派生子进程,exec版本很好,但类型版本会出现错误,如this postthis post中所述(有关更完整的堆栈跟踪,请参阅它们):

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': ''})

似乎模块是不同的,这可能是差异的来源

使用python3.6、windows10、luigi2.8.9。你知道吗

问题:

有没有办法用type来创建一个类,使它的模块是定义它的模块,而不是在abc中?你知道吗

这两种方法之间还有什么不同之处吗?根据this post,应该没有区别,但我不认为是这样。你知道吗


Tags: 模块方法name类型管道thispostsystem
1条回答
网友
1楼 · 发布于 2024-04-19 11:59:28

出现问题的原因是:

  • 在Windows中,子进程无权访问父变量。你知道吗
  • Luigi Tasks使用Register(以及ABC的扩展)作为它的元类。你知道吗
  • 当动态创建一个以ABC(抽象基类)为元类的类时,该类的模块将是abc,而不是定义该类的模块的名称。你知道吗

当一个工人被分配一个任务时,它将进入模块来加载任务。由于模块被设置为abc,而不是动态创建类的模块,因此它将失败。你知道吗

要使其正常工作,只需修改类创建以修改模块:

type(name, (DeliverySystem,),{})

变成

type(name, (DeliverySystem,),{'__module__':__name__})

现在,当工人被分配任务时,它将进入正确的模块并重新创建类,一切都将正常工作!你知道吗

相关问题 更多 >