1、绝对路径引入
Python 在搜索模块时,依次搜索sys.path
里的位置,直到找到模块为止。下面命令可以查看当前的搜索路径:
import sys
print(sys.path)
sys.path
的初始值来源于两个(其实还有一些更复杂但不常用的)。一个是系统的PYTHONPATH
变量,因此可通过设置该变量,来设置 Python 默认的搜索位置。比如:
export PYTHONPATH=/opt/python:$PYTHONPATH
echo $PYTHONPATH
将该命令放在系统初始化脚本(/etc/environment
)或者 BASH 初始化脚本(~/.bashrc
)里,可以对每个新开的窗口有效。
sys.path
的另一个来源是当前执行程序所在的目录 (而不是当前目录)。比如当前目录下文件夹./cc
下有一个b.py
,那么执行./cc/b.py
时,./cc
(而不是./
!)将被加到sys.path
:
python ./cc/b.py
2、相对路径引用
上面说的是搜索模块都是指绝对路径引用。对于非系统目录,就需要操纵sys.path
。但操纵sys.path
有外溢效果,因为它是一个全局变量。对于同一个库里的模块的互相引用,可以考虑使用相对路径:
from . import abc
from .abc import fool
from ..up import foo
但相对路径有两个很恶心的问题,使得用法极为受限。其中一个是:
Note that both explicit and implicit relative imports are based on the name of the current module. Since the name of the main module is always
__main__
, modules intended for use as the main module of a Python application should always use absolute imports.
包含相对路径 import 的 python 脚本不能直接运行,只能作为 module 被引用。原因正如手册中描述的,所谓相对路径其实就是相对于当前 module 的路径,但如果直接执行脚本,这个 module 的 name 就是__main__
, 而不是 module 原来的 name , 这样相对路径也就不是原来的相对路径了,导入就会失败。
在使用相对引用的文件中,不能有 __main__ 方法,只执行作为一个 module 进行引用,而不是直接执行脚本。
举个简单例子。假设./cc/
目录下已有一个./cc/b.py
(内容为空)。当前目录下的./a.py
内容为:
from .cc import b
那么直接运行python ./a.py
将会报错:
ModuleNotFoundError: No module named '__main__.cc'; '__main__' is not a package
另一个是常见的错误是: ValueError: attempted relative import beyond top-level package
。详细介绍:https://www.cnblogs.com/ArsenalfanInECNU/p/5346751.html。
注意不光是无法直接执行,imp.load_source
以及用importlib.util
实现的类似功能,都无法导入这样的文件模块。因此相对引入在实际应用中使用极为受限。
Q. E. D.