Выход байткодом приведены здесь для Python 3.4, но код для получения байткод должен работать на любой версии и те же общие принципы применимы.
Harness:
from dis import dis
def compile_and_dis(src):
dis(compile(src, '<string>', 'exec'))
Случай 1:
>>> compile_and_dis('from module.submodule import someclass as myclass')
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (('someclass',))
6 IMPORT_NAME 0 (module.submodule)
9 IMPORT_FROM 1 (someclass)
12 STORE_NAME 2 (myclass)
15 POP_TOP
16 LOAD_CONST 2 (None)
19 RETURN_VALUE
Это единственный подход, который только добавляет одно имя (myclass
) в текущий locals()
(т.е. __dict__
, который станет globals()
за все определенный в модуле). Это также самый короткий байт-код.
Этот метод поднимет ImportError
, если someclass
не найден в module.submodule
. Однако он попытается загрузить module.submodule.someclass
в качестве модуля.
Случай 2:
>>> compile_and_dis('from module.submodule import someclass; myclass = someclass')
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (('someclass',))
6 IMPORT_NAME 0 (module.submodule)
9 IMPORT_FROM 1 (someclass)
12 STORE_NAME 1 (someclass)
15 POP_TOP
16 LOAD_NAME 1 (someclass)
19 STORE_NAME 2 (myclass)
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
Это почти идентично случаю 1, за исключением того, что она протекает второе имя (someclass
) в локальное пространство имен. Если импорт и назначение не смежны, вы выполняете теоретический риск повторного использования имени для чего-то другого, но если вы затеняете имена, у вас есть ужасный дизайн в любом случае.
Обратите внимание на бесполезный цикл STORE_NAME
/LOAD_NAME
в байтекоде (вокруг несвязанного POP_TOP
).
Случай 3:
>>> compile_and_dis('from module import submodule; myclass = submodule.someclass')
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (('submodule',))
6 IMPORT_NAME 0 (module)
9 IMPORT_FROM 1 (submodule)
12 STORE_NAME 1 (submodule)
15 POP_TOP
16 LOAD_NAME 1 (submodule)
19 LOAD_ATTR 2 (someclass)
22 STORE_NAME 3 (myclass)
25 LOAD_CONST 2 (None)
28 RETURN_VALUE
Этот подход просачивается submodule
в локальное пространство имен. Он не поднимает ImportError
, если класс не найден, скорее он поднимает AttributeError
во время назначения. Он не пытается загрузить module.submodule.someclass
в качестве модуля (и на самом деле даже не волнует, является или нет module.submodule
).
Случай 4:
>>> compile_and_dis('import module.submodule as submodule; myclass = submodule.someclass')
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (module.submodule)
9 LOAD_ATTR 1 (submodule)
12 STORE_NAME 1 (submodule)
15 LOAD_NAME 1 (submodule)
18 LOAD_ATTR 2 (someclass)
21 STORE_NAME 3 (myclass)
24 LOAD_CONST 1 (None)
27 RETURN_VALUE
Это похоже на случай 3, но требует, чтобы module.submodule
быть модулем.
Случай 5:
>>> compile_and_dis('import module.submodule; myclass = module.submodule.someclass')
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (module.submodule)
9 STORE_NAME 1 (module)
12 LOAD_NAME 1 (module)
15 LOAD_ATTR 2 (submodule)
18 LOAD_ATTR 3 (someclass)
21 STORE_NAME 4 (myclass)
24 LOAD_CONST 1 (None)
27 RETURN_VALUE
Этот подход аналогичен случаю 4, хотя 2 атрибутов нагрузки в различных местах, так что другой переменной утечки в локальное пространство имен.
Фактически то же самое. –
Там * есть * отличия, проверьте байт-код. – o11c
То же самое, u назначает его переменной в глобальном пространстве вашего текущего скрипта. – Ja8zyjits