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。解决顺序:

  1. 优先重构代码,拆分依赖,移动共享逻辑到第三个模块,避免循环引用。
  2. 如果短期应对,可将某些导入语句移到函数或方法内部以延迟导入(慎用,违背将导入置于文件顶部的惯例)。

总的原则是尽量重构而非依赖延迟导入来“修补”循环依赖。

参考链接