2015-07-30 2 views
4

Как отличаются следующие два утверждения и каковы последствия каждого из них?Разница между Python между 'import as' и присваиванием переменной

Импорт как:

from module.submodule import someclass as myclass 

Присвоить переменной:

from module.submodule import someclass 
myclass = someclass 
+0

Фактически то же самое. –

+1

Там * есть * отличия, проверьте байт-код. – o11c

+0

То же самое, u назначает его переменной в глобальном пространстве вашего текущего скрипта. – Ja8zyjits

ответ

2

Выход байткодом приведены здесь для 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 атрибутов нагрузки в различных местах, так что другой переменной утечки в локальное пространство имен.

+1

Это очень полезно! –

4

Основное отличие заключается в том, что в вашей переменной, например присваивания, someclass по-прежнему доступен в качестве имени. Это приведет к проблемам при импорте типов с тем же именем.

from datetime import datetime 
from arrow import datetime # problem! 

Чтобы это исправить:

from datetime import datetime 
from arrow import datetime as arrow_datetime 
+0

Любые идеи, почему PyCharm не может показать быстрое определение или перейти к исходному коду 'someclass.some_attribute_or_method', когда я использую второй подход (присваивание переменной), но он отлично работает, когда я использую первый? –

Смежные вопросы