这里提供的字节码输出是针对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
这是唯一一种方法,只向当前的locals()
(即__dict__
,对于在模块中定义的所有内容将变为globals()
)中添加一个名称(myclass
)。而且,这也是最短的字节码。
如果在module.submodule
中找不到someclass
,则此方法会引发ImportError
。然而,它将尝试将module.submodule.someclass
作为模块加载。
情况2:
>>> compile_and_dis('from module.submodule import 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
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
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
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个属性加载在不同的位置,因此不同的变量泄漏到本地命名空间。