“导入为”与变量赋值之间的Python差异

时间:2015-07-30 06:16:46

标签: python import python-import

以下两个陈述有何不同?每个陈述的后果是什么?

导入为:

from module.submodule import someclass as myclass

分配给变量:

from module.submodule import someclass
myclass = someclass

2 个答案:

答案 0 :(得分:4)

主要区别在于,在您的变量赋值示例中,someclass仍然可用作名称。导入具有相同名称的类型时会导致问题。

from datetime import datetime
from arrow import datetime  # problem!

解决此问题:

from datetime import datetime
from arrow import datetime as arrow_datetime

答案 1 :(得分:3)

此处给出的字节码输出适用于Python 3.4,但生成字节码的代码应适用于任何版本,并且适用相同的一般原则。

线束:

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个属性加载位于不同的位置,因此不同的变量会泄漏到本地名称空间中。