6

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

src/
    core/
        stuff/
        tools/
            tool1.py
            tool2.py
    gui/
        morestuff/
        gui.py

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

python src/core/tools/tool2.py
python src/gui/gui.py

现在所有工具都导入自src.core.stuff,而 GUI 需要gui.morestuff。这意味着sys.path[0]应该指向src/,但它默认指向src/core/tools/or 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]))

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

python -m gui.gui

但这需要当前目录为src/.

有没有更好的方法来达到预期的结果,例如通过修改__init__.py文件?

编辑:这适用于 Python 2.7:

~$ python -V
Python 2.7.3
4

3 回答 3

5

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

现在,进行python -m mypackage.mymodule工作需要您位于项目的顶级文件夹(src在您的情况下),或者该顶级文件夹位于 Python 搜索路径上。要求您位于特定文件夹中很尴尬,并且您已经说过您不希望这样做。进入src搜索路径是我们的目标。

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

该解决方案设置简单(环境变量可以在您的 或其他等效位置自动设置.profile.bashrc,并且适用于任意数量的脚本。如果您移动您的项目,只需更新您的环境设置,您就可以完成所有设置,而无需为每个脚本做更多的工作。

于 2013-04-04T11:29:59.603 回答
4

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

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

蟒蛇路径

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

PYTHONPATH=/src python src/gui/gui.py

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

网站包

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

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

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

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

virtualenv 和打包

最好的解决方案就是硬着头皮做真正的python打包。这与强大的工具(如virtualenv 和 pip )相结合,让您拥有一个隔离(或半隔离)的 Python 环境。

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

一个缺点是您必须编写和维护一个setup.py将指示pip(python 安装程序)将您的软件包含在 virtualenv 中的程序。内容将类似于:

!/usr/bin/env 蟒蛇
# -*- 编码: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

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

env/bin/tool1.py
于 2013-04-17T05:32:14.113 回答
1

我想这样做是为了避免首先设置 PYTHONPATH

您可以在其他地方sys.path使用该模块来挂钩 Python 的初始化,该site模块(默认情况下)在 Python 初始化时自动导入。

基于此代码site.py...

# Prefixes for site-packages; add additional prefixes like /usr/local here
PREFIXES = [sys.prefix, sys.exec_prefix]

...看起来好像该文件的目的是在安装后修改该文件,这是一种选择,尽管它还提供了其他可以影响的方式sys.path,例如通过将.pth文件放在site-packages目录中的某个位置。

假设所需的结果是使代码“开箱即用”,这将起作用,但仅适用于单个系统上的所有用户。

如果您需要它在多个系统上工作,那么您必须对所有系统应用相同的更改。

对于部署来说,这没什么大不了的。事实上,许多 Python 包已经做了类似的事情。例如在 Ubuntu 上...

~$ dpkg -L python-imaging | grep pth
/usr/share/pyshared/PIL.pth
/usr/lib/python2.7/dist-packages/PIL.pth

...但是,如果您的目的是让多个并发开发人员更容易,每个开发人员都使用自己的系统,那么您最好坚持使用当前选项,将一些“样板”代码添加到每个打算运行的 Python 模块作为脚本。

可能还有另一种选择,但这取决于您要实现的目标。

于 2013-04-16T11:59:23.617 回答