当主脚本在子模块中时,正确初始化sys.path

krl*_*mlr 5 python module path python-import

sys.path根据文档,第一个条目是当前脚本的目录.在以下设置中,我想更改此默认值.想象一下以下目录结构:

src/
    core/
        stuff/
        tools/
            tool1.py
            tool2.py
    gui/
        morestuff/
        gui.py
Run Code Online (Sandbox Code Playgroud)

脚本tool*.pygui.py旨在为运行脚本,如下所示:

python src/core/tools/tool2.py
python src/gui/gui.py
Run Code Online (Sandbox Code Playgroud)

现在所有工具都从中导入src.core.stuff,并且需要GUI gui.morestuff.这意味着sys.path[0]应该指向src/,但它指向src/core/tools/src/gui/默认.

我可以调整sys.path[0]每个脚本(使用类似下面的结构,例如,在开头gui.py):

if __name__ == '__main__':
    if sys.path[0]: sys.path[0] = os.path.dirname(os.path.abspath(sys.path[0]))
Run Code Online (Sandbox Code Playgroud)

但是,这有点多余,对于拥有数千个脚本的成熟代码库来说,这将变得乏味.我也知道-m开关:

python -m gui.gui
Run Code Online (Sandbox Code Playgroud)

但这需要当前目录src/.

有没有更好的方法来实现所需的结果,例如通过修改__init__.py文件?

编辑:这是为Python 2.7:

~$ python -V
Python 2.7.3
Run Code Online (Sandbox Code Playgroud)

Blc*_*ght 5

运行程序包中脚本的唯一官方批准方法是使用-m标志.虽然您可以直接运行脚本并尝试sys.path在每个脚本中自己进行操作,但这可能会非常痛苦.如果在文件夹之间移动脚本,sys.path则还可能需要更改重写逻辑以反映新位置.即使你做sys.path对了,显式相对导入也无法正常工作.

现在,制作python -m mypackage.mymodule工作需要您在项目的顶级文件夹(src在您的情况下),或者要在Python搜索路径上的顶级文件夹.要求你在一个特定的文件夹是很尴尬的,你已经说过你不想这样.获取src入搜索路径是那么我们的目标.

我认为最好的方法是使用PYTHONPATH环境变量将解释器指向项目的src文件夹,以便它可以从任何地方找到您的包.

该解决方案是简单的设置(环境变量可以自动在你的设置.profile,.bashrc或者一些其他等同的地方),并为任意数量的脚本工作.如果您移动项目,只需更新您的环境设置,您就可以全部设置,而无需为每个脚本做更多的工作.


rhe*_*ttg 4

这里有三个基本选项。我在生产环境和个人项目中都经历过这三个过程。在许多方面,它们是相互借鉴的。不过,我的建议是跳到最后一个。

根本问题是你需要你的./src目录位于 python 搜索路径中。这确实是 python 打包的意义所在。

Python路径

调整 python 路径的最直接、用户定义的方法是通过环境变量PYTHONPATH。您可以在运行时设置它,执行以下操作:

PYTHONPATH=/src python src/gui/gui.py
Run Code Online (Sandbox Code Playgroud)

当然,您也可以在全局环境中进行设置,因此希望所有需要它的进程都能找到正确的PYTHONPATH. 但是,请记住,你总会忘记一个。通常在凌晨 3 点,您的cron任务最终运行。

网站套餐

为了避免需要环境变量,您的选择几乎是将您的软件包含在源路径的现有条目中,或者找到一些其他方法来添加新的搜索路径。因此,这可能意味着将目录的内容拖放src/usr/lib/python2.7/site-packages系统site-packages所在的位置或任何位置。

由于您可能不想实际将代码包含在站点包中,因此您可以为两个子包创建符号链接。

由于多种原因,这当然不太理想。如果您在命名时不小心,那么机器上的每个 python 程序都会突然面临潜在的名称冲突。您正在向计算机上的每个用户公开您的软件。如果 python 更新,您可能会遇到问题。如果添加新的子包,现在您必须创建新的符号链接。

.pth稍微好一点的方法是在站点包中的某个位置包含一个文件。当 python 遇到这些文件时,它会将内容(应该是目录的名称)添加到搜索路径中。这避免了必须记住为每个新子包添加新符号链接的问题。

虚拟环境和打包

最好的解决办法就是硬着头皮做真正的python打包。这与virtualenv 和 pip 等优秀工具相结合,让您拥有一个隔离(或半隔离)的 python 环境。

在 virtualenv 下,您可以为您的项目进行自定义site-packages,您可以轻松地将软件安装到其中,从而避免早期解决方案的所有问题。virtualenv 还可以轻松维护可执行脚本,使其运行的 python 环境完全符合您的预期。

一个缺点是你必须编写和维护一个setup.py命令pip(python 安装程序)将你的软件包含在 virtualenv 中。内容大概是这样的:

!/usr/bin/env python
# -*- 编码:utf-8 -*-

从 distutils.core 导入设置


设置(
    名称='我的项目',
    package_dir={'myproject': 'src'},
    脚本=['src/gui/gui.py', 'src/core/tools/tool1.py', 'src/core/tools/tool2.py']
)

因此,要设置这个环境,它看起来像这样:

virtualenv env
env/bin/pip install -e setup.py
Run Code Online (Sandbox Code Playgroud)

要运行你的脚本,你只需执行以下操作:

env/bin/tool1.py
Run Code Online (Sandbox Code Playgroud)