【问题标题】:Python difference between 'import as' vs variable assignment“导入为”与变量赋值之间的Python区别
【发布时间】:2023-03-14 22:01:02
【问题描述】:

以下两种说法有何不同,各自的后果是什么?

导入为:

from module.submodule import someclass as myclass

赋值给一个变量:

from module.submodule import someclass
myclass = someclass

【问题讨论】:

  • 实际上是一样的。
  • 个不同,检查字节码。
  • 同样的事情,你将它分配给你当前脚本的全局空间中的一个变量
  • PyCharm for one 无法显示快速定义或转到源代码,当我使用第二种方法(分配给变量)时,但当我使用第一种方法时它工作正常。

标签: python import python-import


【解决方案1】:

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

线束:

from dis import dis

def compile_and_dis(src):
    dis(compile(src, '<string>', 'exec'))

案例一:

>>> 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())的唯一方法。也是最短的字节码。

如果在module.submodule 中找不到someclass,此方法将引发ImportError。但是,它会尝试将 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 个属性加载在不同的位置,因此不同的变量会泄漏到本地命名空间中。

【讨论】:

  • 这很有帮助!
【解决方案2】:

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

from datetime import datetime
from arrow import datetime  # problem!

解决这个问题:

from datetime import datetime
from arrow import datetime as arrow_datetime

【讨论】:

  • 任何想法为什么 PyCharm 无法在 someclass.some_attribute_or_method 上显示快速定义或转到源代码,当我使用第二种方法(分配给变量)时,但当我使用第一种方法时它工作正常?跨度>
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 2016-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多