关于python import的sys.path路径问题

关于python import的sys.path路径问题

sys.path

先说一下 sys.path 这个变量,该变量需要导入 sys 官方库方可使用,它是一个列表,是当前 python 文件 import 库时会逐个搜索列表中的路径。

初始化

sys.path 从这些位置初始化:

  • 包含输入脚本的目录(或当前目录,当没有指定文件时)
  • PYTHONPATH(目录名列表,与 shell 变量 PATH 语法相同)
  • 与安装相关的默认值(比如当前conda环境的路径)

添加

为了解决上述问题,需要添加模块搜索路径,可以使用以下几种方式:

  • 动态增加路径

    临时生效,对于不经常使用的模块,这通常是最好的方式,因为不必用所有次要模块的路径来污染 PYTHONPATH。

    import sys
    sys.path.append('/home/song/mylib')
    
  • 修改 PYTHONPATH 变量

    永久生效,对于在许多程序中都使用的模块,可以采用这种方式。这将改变所有 Python 应用的搜索路径,因为启动 Python 时,它会读取这个变量,甚至不同版本的 Python 都会受影响。

    export PYTHONPATH=$PYTHONPATH:/home/song/mylib
    

    直接命令行执行则当前终端生效,或添加到 ~/.bashrc 中并 source 永久生效。

  • 增加 .pth 文件

    永久生效,这是最简单的、也是推荐的方式。Python 在遍历已知的库文件目录过程中,如果遇到 .pth 文件,便会将其中的路径加入到 sys.path 中,于是 .pth 中所指定的路径就可以被 Python 运行环境找到了。

    /usr/local/lib/python3.5/site-packages 下添加一个扩展名为 .pth 的配置文件(例如:extras.pth),内容为要添加的路径:/home/song/mylib

例子

考虑这样一个目录结构,他基本涵盖我们 python 文件 import 自定义库时的情况:

.
├── lib1.py
├── t1
│   ├── lib0.py
│   └── test.py
└── t2
    └── lib2.py

我们的 test.py 想要 import lib0、1、2.py 三个库文件,并且,我们要考虑在 test.py 的当前目录运行(python test.py) 或其父目录运行(python t1/test.py)时,分别应该怎么做呢?

导入lib0

当前目录运行

首先要明确,我们的 python 程序在考虑相对路径时,考虑的是文件所在目录的相对路径,而不是工作目录的路径。所以我们直接导入即可:

import lib0

父目录运行

刚才提到这不受到工作目录影响,所以同上。

导入lib1

当前目录运行

我们都知道,要导入上级目录的文件,可以通过在 sys.path 中追加上级目录 .. 来实现。另一个关键点就在这里,sys.path 中的相对路径是相对工作目录而言的,而不是相对文件所在目录。因此我们在当前目录运行时:

import sys
sys.append('..')

import lib1

运行:python test.py

父目录运行

注意这里就有所不同了,因为 sys.path 是相对工作目录而言的,我们在父目录运行程序,工作目录变化了,因此应该:

import sys
sys.append('.')

import lib1

导入lib2

实际导入 lib2 就与导入 lib1 类似,只是多一级即可

当前目录运行

import sys
sys.append('..')

import t2.lib1

父目录运行

import sys
sys.append('.')

import t2.lib1

Ref:

Python 模块搜索路径