Python import 的搜索路径
Python 在导入模块时按顺序搜索以下位置:
- 当前目录
- 环境变量 PYTHONPATH 中指定的路径(按顺序)
- Python 安装目录下的标准库路径
可以通过 sys.path 查看当前的搜索路径。了解这些路径有助于调试模块无法找到或导入错误的问题。
绝对导入
常见的绝对导入形式:
import foo
import foo.bar
import foo as bar
from foo import bar
尽量避免使用 from foo import *
,因为它会污染命名空间,可能与本地定义冲突,导致难以发现的错误。
相对导入
PEP 328 引入了相对导入的语法,用点号表示相对层级:
from .foo import bar # 从当前包的同级或子模块导入
from ..foo import bar # 从上一级包中导入
注意含相对导入的模块不能作为顶层脚本直接运行,会报错:
ValueError: Attempted relative import in non-package
原因是 Python 通过模块的 __name__
来判断其包结构。如果直接执行一个模块,__name__
会是 "__main__"
,此时没有包层级信息,导致相对导入失败。
如果确实需要运行某个包内模块作为脚本,可以通过调整 sys.path 将包的父目录加入搜索路径,或使用 python -m package.module
的方式运行。
相对导入与绝对导入的概念主要在包内部有意义——如果两个文件在同一目录且该目录不是包(没有 __init__.py
),那么它们分别作为独立模块被导入,不存在相对/绝对导入的区别。
导入注意事项
循环导入
当两个模块互相导入对方时,会出现循环导入问题,通常表现为在访问对方模块的对象时出现 AttributeError 或者对象为 None。解决顺序:
- 优先重构代码,拆分依赖,移动共享逻辑到第三个模块,避免循环引用。
- 如果短期应对,可将某些导入语句移到函数或方法内部以延迟导入(慎用,违背将导入置于文件顶部的惯例)。
总的原则是尽量重构而非依赖延迟导入来“修补”循环依赖。