У меня есть трубопровод Луиджи. У нас много и много внешних файлов, которые меняются на регулярной основе, и мы хотим иметь возможность строить конвейер из метаданных.
Я создаю классы динамически, и нашел два способа сделать это:
Использование exec:
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': ''})
Кажется, что модуль отличается, и это может быть источником различий.
Использование Python3,6, Windows 10, Луиджи 2,8,9.
Вопросы:
Есть ли способ использовать type
для создания класса, чтобы его модуль был модулем, в котором он определен, а не в abc
?
Есть ли какая-то другая разница, которую мне не хватает между методами? Согласно этому посту не должно быть никакой разницы, но я не считаю, что это так.