Python与';导入为';变量赋值
以下两种说法有何不同?每种说法的后果是什么 导入为:Python与';导入为';变量赋值,python,import,python-import,Python,Import,Python Import,以下两种说法有何不同?每种说法的后果是什么 导入为: from module.submodule import someclass as myclass 分配给变量: from module.submodule import someclass myclass = someclass 主要区别在于,在变量赋值示例中,someclass仍然可用作名称。这将导致导入具有相同名称的类型时出现问题 from datetime import datetime from arrow import dat
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
这里给出的字节码输出是针对Python3.4的,但是生成字节码的代码应该适用于任何版本,并且相同的一般原则也适用 线束:
from dis import dis
def compile_and_dis(src):
dis(compile(src, '<string>', 'exec'))
这是唯一一种只将一个名称(myclass
)添加到当前locals()
(即\uuu dict\uuu
,对于模块中定义的所有内容,它将成为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
)泄漏到本地名称空间中。如果导入和赋值不是连续的,那么在理论上可能会将名称重新用于其他用途,但是如果要隐藏名称,那么无论如何设计都很糟糕
注意字节码中无用的存储\u名称
/加载\u名称
循环(围绕一个不相关的弹出顶部
)
案例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
这种方法将子模块
泄漏到本地命名空间中。如果找不到类,它不会引发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类似,但要求模块。子模块
是一个模块
案例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个属性加载位于不同的位置,因此不同的变量泄漏到本地名称空间。实际上是相同的事情。如果存在差异,请检查字节码。同样的事情,当我使用第二种方法(赋值到变量)时,您正在将其赋值到当前脚本的全局空间中的变量,因为其中一个无法显示快速定义或转到源代码,但是当我使用第一种方法时,它工作得很好。你知道为什么PyCharm不能在
someclass上显示快速定义或转到源代码吗?当我使用第二种方法(赋值到变量)时,某些属性或方法
,但当我使用第一种方法时,它工作得很好吗?这非常有用!
>>> 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