PYTHONPATH应该设置什么?

106

我正在为工作中的其他开发人员编写一个Python项目的设置文档,我一直在阅读关于 PYTHONPATH 环境变量的内容。我正在查看我的当前开发系统,并认为我设置了一些错误的东西,导致我的IDE (IntelliJ) 在查找Python库时表现不正确。

我查看了 这里这里 的文档,但仍不确定 PYTHONPATH 环境变量应该实际包含什么。

我已经将 PYTHONHOME 指向 C:\Python27

我的当前 PYTHONPATH 设置为 PYTHONHOME。我应该也将 sys.path 中的目录添加进去吗?

更新:

根据以下信息,除非有非标准库需要Python默认查找,否则不需要设置 PYTHONPATH。例如,当我从安装程序安装 wxPython 时,它会将其库添加到 PYTHONPATH 中。我将 PYTHONHOME 设置为 Python 安装的根目录,以便将其添加到系统的 PATH 环境变量中,这样我就可以从任何地方运行 Python。

4个回答

66
你不必设置它们中的任何一个。可以将PYTHONPATH设置为指向包含私有库的其他目录。 PYTHONHOME设置默认库的位置。 文档PYTHONHOME 更改标准Python库的位置。默认情况下,在prefix/lib/pythonversionexec_prefix/lib/pythonversion中搜索库,其中prefixexec_prefix是安装相关的目录,两者都默认为/usr/local。
当将PYTHONHOME设置为单个目录时,其值将替换prefixexec_prefix。要为它们指定不同的值,请将PYTHONHOME设置为prefix:exec_prefixPYTHONPATH 增加模块文件的默认搜索路径。格式与shell的PATH相同:一个或多个目录路径名,由os.pathsep分隔(在Unix上为冒号,在Windows上为分号)。不存在的目录会被静默忽略。
除了普通目录外,各个PYTHONPATH条目还可以引用包含纯Python模块(以源代码或编译形式)的zip文件。无法从zip文件导入扩展模块。
默认搜索路径是与安装有关的,但通常以prefix/lib/pythonversion开头(请参见上面的PYTHONHOME)。它始终会追加到PYTHONPATH后面。
Interface options下面所述的方式前,将在搜索路径中插入一个附加目录。可以通过变量sys.path在Python程序内部操作搜索路径。

6
默认情况下,PYTHONHOME实际上指向标准库的目录(例如,/usr/local/lib/pythonXX)。 - Ferdinand Beyer
2
@Ferdinand 不是在Windows上。它没有设置。但重点是,除非用户有一个与默认库不同的私有目录,否则他们通常不必去处理它们中的任何一个。 - Mark Tolonen
3
当然它没有被设置 - Python从不设置环境变量。但是有一个内部等价的PYTHONHOME可以使用环境变量来 覆盖。我说的是这个内部变量的默认值。 - Ferdinand Beyer
4
“Ferdinand Beyer”说:“当然没有设置——Python从未设置环境变量。”不过最新的 Python 3.3 至少可以将自己添加到 PATH 变量中。值得注意。 - twobob

28

对于大多数安装,您不应设置这些变量,因为它们不是Python运行所必需的。 Python知道如何找到其标准库。

仅在需要维护自定义Python库目录(即不想安装在全局默认位置(即site-packages目录))时才设置PYTHONPATH。

请务必阅读:http://docs.python.org/using/cmdline.html#environment-variables


4
好的,那么你不应该这样做。但是你应该怎么做呢?你想要运行路径中的模块,并且不希望源代码保存路径(不是相对路径,也绝对不是静态路径)。 - pashute

7
这是我所学到的:PYTHONPATH是一个目录,可添加到Python导入搜索路径“sys.path”中,该路径由当前目录CWD、PYTHONPATH、标准和共享库以及客户端库组成。例如:
% python3 -c "import sys;print(sys.path)"
['', 
'/home/username/Documents/DjangoTutorial/mySite', 
'/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', 
'/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']

第一个路径“”表示当前目录,第二个路径通过

%export PYTHONPATH=/home/username/Documents/DjangoTutorial/mySite 

可以添加到~/.bashrc使其永久化,其余部分是Python标准和动态共享库(dynamic shared library)以及第三方库如django。

如上所述,请勿混淆PYTHONHOME,即使将其设置为''或'None'也会导致python3 shell停止工作:

% export PYTHONHOME=''
% python3
Fatal Python error: Py_Initialize: Unable to get the locale encoding
ModuleNotFoundError: No module named 'encodings'

Current thread 0x00007f18a44ff740 (most recent call first):
Aborted (core dumped)

请注意,如果您启动一个Python脚本,当前工作目录将是脚本所在的目录。例如:
username@bud:~/Documents/DjangoTutorial% python3 mySite/manage.py runserver
==== Printing sys.path ====
/home/username/Documents/DjangoTutorial/mySite # CWD is where manage.py resides
/usr/lib/python3.6
/usr/lib/python3.6/lib-dynload
/usr/local/lib/python3.6/dist-packages
/usr/lib/python3/dist-packages

您可以在运行时将路径附加到sys.path: 假设您的文件Fibonacci.py在~/Documents/Python目录中:
username@bud:~/Documents/DjangoTutorial% python3 
>>> sys.path.append("/home/username/Documents")
>>> print(sys.path)
['', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', 
'/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages', 
'/home/username/Documents']
>>> from Python import Fibonacci as fibo

或通过

% PYTHONPATH=/home/username/Documents:$PYTHONPATH
% python3
>>> print(sys.path)
['', 
'/home/username/Documents', '/home/username/Documents/DjangoTutorial/mySite', 
'/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', 
'/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
>>> from Python import Fibonacci as fibo

1
一个比直接操作 PYTHONPATH 更少“临时性”的解决方案是使用带有 -e 标志的 pip 命令,它可以无缝地安装本地库以便导入和重新导入以反映所做的更改。
为了能够像导入任何其他模块一样导入 mypackage,正确的方法是在本地使用 pip: python -m pip install -e /path_to_package/mypackage/
  • python -m 确保您使用的是与当前使用的 python 安装相同的 pip 包。

  • -e 使其可编辑,即在您进行更改后,import mypackage 将重新加载,而不是使用缓存的版本。

mypackage 必须是可安装的包,即包含一个 __init__.py 文件和一个基本的 setup.py(对于 pipenv,则为 pyproject.toml 文件)。 minimal setup.py
from setuptools import find_packages, setup

setup(
    name='mypackage',          # Required
    version='0.0.1',           # Required
    packages=find_packages(),  # Required
)

包结构必须如下所示:

mypackage/
    setup.py
    mypackage/    <----- this is a folder inside the other `mypackage/` folder
        __init__.py

或者作为一棵树:
└── python_perso                folder
    └── mypackage                   folder
        ├── mypackage                   folder
           └── __init__.py
        └── setup.py

[编辑] 安装后,目录将如下所示:
(对于名为mypackage的软件包)

└── python_perso
    └── mypackage
        ├── mypackage
        │   ├── __init__.py
        │   └── __pycache__
        │       └── __init__.cpython-38.pyc
        ├── mypackage.egg-info
        │   ├── PKG-INFO
        │   ├── SOURCES.txt
        │   ├── dependency_links.txt
        │   └── top_level.txt
        └── setup.py

5 directories, 7 files

“-e”选项并不会自动重新加载!它只是意味着您的软件包文件将从它们所在的位置使用,而不是复制到“site-packages”目录中。 - MarSoft
“重启内核”是什么意思? 当您重新启动脚本时,新启动的Python进程将从其声明的路径导入模块。如果您使用了pip install命令而没有加上-e选项,则您的文件将被从原来的位置复制到site-packages目录,并从那里加载。如果您修改了文件,则在重新安装带有pip install命令的内容之前,site-packages中的副本不会被编辑。 - MarSoft
现在,当你使用 pip install -e(也就是 --editable)时,pip会在 site-packages 中创建一个特殊的文件,名为 MYMODULE.egg-link ,并包含模块的原始位置的完整路径(例如 /home/user/work/mymodule),Python会从这里加载模块文件。因此,如果您编辑了模块文件,则任何后续的导入都将使用已更新的文件,而无需再次使用 pip install 更新 site-packages 的副本。值得注意的是,import 是有缓存的,所以它们不会被“自动更新”,直到您重新启动Python进程或使用 importlib.reload 为止。 - MarSoft
谢谢您提供这些重要的澄清,您比我解释得更好。 - Reblochon Masque

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接