Импорт динамического модуля из внешней функции (или - редактирование globals() вне модуля) в Python

У меня есть проект, в котором я хочу неоднократно изменять код в классе, а затем запускать другие модули для проверки изменений (проверки..). В настоящее время после каждого редактирования мне приходится перезагружать код, модули тестирования, которые его запускают, а затем запускать тест. Я хочу сократить этот цикл до одной строки, более того, я потом захочу протестировать разные классы, поэтому я хочу иметь возможность получать в качестве параметра имя тестируемого класса — значит, мне нужен динамический импорт.

Написал функцию для чистого импорта любого модуля, вроде работает:

def build_module_clean(module_string,attr_strings):
    module = import_module(module_string)
    module = reload(module)
    for f in attr_strings:
        globals()[f]=getattr(module,f)

Теперь, во имя чистоты, я хочу сохранить эту функцию в модуле-оболочке (который будет содержать однострочник, который я хочу каждый раз пересобирать и тестировать весь код) и запускать его из разных модулей, т.е. операторы импорта моего модуля ModelChecker я бы поместил строку

from wrapper import build_module_clean
build_module_clean('test_class_module',['test_class_name'])

однако, когда я это делаю, кажется, что тестовый класс добавляется к глобалам в модуле-оболочке, но не в модуле ModelChecker (попытка доступа к globals()['test_class_name'] в ModelChecker дает ключевую ошибку). Я пытался передать globals или globals() в качестве дополнительных параметров для build_module_clean, но globals - это функция (поэтому тестовый модуль все еще загружается в оболочку globals), и передача, а затем использование globals() дает ошибку

TypeError: 'builtin_function_or_method' object does not support item assignment

Поэтому мне нужен какой-то способ редактировать globals() одного модуля из другого модуля.


В качестве альтернативы (в идеале?) Я хотел бы импортировать модуль test_class в оболочку таким образом, чтобы сделать его видимым для всех модулей, которые его используют (например, ModelChecker). Как я могу это сделать?


person gail    schedule 24.02.2016    source источник


Ответы (1)


Ваша функция должна выглядеть так:

def build_module_clean(globals, module_string, attr_strings):
    module = import_module(module_string)
    module = reload(module)
    globals[module_string] = module
    for f in attr_strings:
        globals[f] = getattr(module, f)

и назовите это так:

build_module_clean(globals(), 'test_class_module', ['test_class_name'])

Объяснение:

Вызов globals() в вызове функции (build_module_clean(globals()...) захватывает __dict__ модуля, все еще находясь в правильном модуле, и передает его вашей функции.

Затем функция может (повторно) присвоить имена вновь загруженному модулю и его текущим атрибутам.

Обратите внимание, что я также (повторно) назначил глобальным переменным только что загруженный модуль (вам может не понадобиться эта часть).

person Ethan Furman    schedule 18.03.2016