Python 'import as' 与变量赋值的区别
Python difference between 'import as' vs variable assignment
以下两种说法有何不同,每种说法的后果是什么?
导入为:
from module.submodule import someclass as myclass
分配给一个变量:
from module.submodule import someclass
myclass = someclass
主要区别在于,在您的变量赋值示例中,someclass
仍可用作名称。这会在导入具有相同名称的类型时导致问题。
from datetime import datetime
from arrow import datetime # problem!
解决这个问题:
from datetime import datetime
from arrow import datetime as arrow_datetime
此处给出的字节码输出适用于 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
作为模块加载。
案例二:
>>> 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
)。
案例三:
>>> 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
泄漏到本地名称空间中。如果未找到 class,它不会引发 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 个属性加载位于不同的位置,因此不同的变量泄漏到本地名称空间中。
以下两种说法有何不同,每种说法的后果是什么?
导入为:
from module.submodule import someclass as myclass
分配给一个变量:
from module.submodule import someclass
myclass = someclass
主要区别在于,在您的变量赋值示例中,someclass
仍可用作名称。这会在导入具有相同名称的类型时导致问题。
from datetime import datetime
from arrow import datetime # problem!
解决这个问题:
from datetime import datetime
from arrow import datetime as arrow_datetime
此处给出的字节码输出适用于 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
作为模块加载。
案例二:
>>> 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
)。
案例三:
>>> 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
泄漏到本地名称空间中。如果未找到 class,它不会引发 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 个属性加载位于不同的位置,因此不同的变量泄漏到本地名称空间中。