咱们在 Python 中,总是应用 import 来导入另外一个模块(文件)中的内容,如果是从 Java 或 C 转过来的程序员,有几个常见的坑要留神一下:
-
import 也是执行语句,能够在代码任何部位执行。如果咱们把 import 写在代码两头,IDE 很可能会有个正告,但只有逻辑正确,就不必理它:
import a if __name__ == "__main__": import b b.methodx()
相似以上代码,只有以后文件作为主模块运行的时候,才导入模块 b,岂但缩小了节约,而且有可能防止循环援用。
- import 执行的时候,如果是第一次导入,那么会把对应模块执行一遍,这个模块里所有的顶级代码都会执行,所以是个很耗时的操作,这点跟 Java 或者 C 只是获取类型定义齐全不同;所以那些被复用的模块,要尽量 缩小在顶级代码块中实现逻辑。
-
即便在同一个模块里,代码定义的程序也很重要,被援用的代码肯定要在援用的后面定义,比方:
class A: x: int = 5 class B: def __init__(self, y: A): self.y = y if __name__ == "__main__": a = A() b = B(a) print(b.y.x)
下面这段代码里就不能把 class A 的定义放在 class B 前面,否则运行时会出错,提醒
name 'A' is not defined
;当然如果仅仅是 annotation 里援用的话,能够通过from __future__ import annotations
来解决,这是另外一个问题了。 - import 的 namespace 也很重要,命名空间不同,会被认为是不同的模块。而一个模块,用绝对路径或者相对路径引入,会被辨认为不同的命名空间,比方上面的 package 构造:
module_a 的内容如下:
a = {"value": 15}
print(f'a={a} in module_a')
module_b 会用绝对路径援用 module_a
from lang.test_import.module_a import a
a['value'] = a['value'] + 1
print(f'a={a} in module_b')
module_c1 和 module_c2 别离用相对路径和绝对路径引入 module_a,再引入 module_b,就会失去不同的后果:
from module_a import a
import module_b
print(f'a={a} in module_c1')
a={'value': 15} in module_a
a={'value': 15} in module_a
a={'value': 16} in module_b
a={'value': 15} in module_c1
from lang.test_import.module_a import a
import module_b
print(f'a={a} in module_c2')
a={'value': 15} in module_a
a={'value': 16} in module_b
a={'value': 16} in module_c2
能够看到在 module_c1 中,module_a 被引入了两次,认作不同的模块,从而也引入了两个变量 a,而 c1 模块,只抵赖本人引入的相对路径命名空间中的 a,所以这里的 a.value,并没有被模块 b 更改。