sys.path中的正确的初始化时,主脚本是在一个子模块(Proper initialization

2019-08-19 08:20发布

的第一个条目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/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

Answer 1:

你在这里有三个基本选项。 我一直都在生产环境和个人项目已通过所有三个。 在许多方面,他们建立在彼此。 然而,我的建议是只跳到最后一个。

最根本的问题是,你需要你的./src目录是在python的搜索路径。 这难道就是蟒蛇的包装是怎么一回事。

PYTHONPATH

最简单的,用户自定义的方式来调整你的Python路径是通过环境变量PYTHONPATH 。 您可以在运行时设置它,做这样的事情:

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

你当然也可以在您的全球环境中设置此所以希望那些需要它会找到正确的所有进程PYTHONPATH 。 但是,只要记住,你总是忘记一个。 通常在凌晨3点的时候你cron任务终于运行。

网站套餐

为了避免需要一个环境变量,你的选择是相当多,包括在源路径中的现有条目您的软件,或者找到一些额外的方式来添加新的搜索路径。 因此,这可能意味着你丢弃的内容src目录复制到/usr/lib/python2.7/site-packages或任何系统site-packages所在。

既然你可能不希望实际上包括站点包的代码,你可以创建你的两个子包一个符号链接。

这是不是很理想有很多原因,当然少。 如果你不小心与当时命名突然机器上的每个Python程序暴露给潜在的名称冲突。 你暴露你的软件的机器上的每个用户。 如果蟒蛇获取的经更新您可能会遇到的问题。 如果你添加一个新的子包,现在你必须创建一个新的符号链接。

一个稍微好一点的方法是包括.pth文件某处您的站点包。 当Python遇到这些文件时,会将内容(这应该是一个目录的名称)的搜索路径。 这样就避免了要记得添加一个新的符号链接为每个新的子包的问题。

的virtualenv和包装

最好的解决方法就是硬着头皮做真正的蟒蛇包装。 这一点,加上像伟大的工具的virtualenv和PIP让您有一个独立(或半隔离)Python环境。

在virtualenv中,你将有一个自定义site-packages的只是你的项目,你可以将软件轻松安装进去,避免了早期解决方案的所有问题。 virtualenv中也可以很容易地保持可执行的脚本,使其运行在Python环境是完全按照你的期望。

一个缺点是,你必须编写和维护一个setup.py这将指示pip (蟒蛇安装程序),包括您在virtualenv中的软件。 内容是这样的:

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

from distutils.core import setup


setup(
    name='myproject',
    package_dir={'myproject': 'src'},
    scripts=['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


Answer 2:

唯一正式批准的方式来运行一个脚本,在包是使用-m标志。 虽然你可以直接运行一个脚本,并尝试做sys.path你自己的操作在每个脚本,它很可能是一个很大的痛苦。 如果移动文件夹之间的脚本,用于重写逻辑sys.path也可能需要改变,以反映新的位置。 即使你sys.path正确,明确的相对进口量将无法正常工作。

现在,让python -m mypackage.mymodule工作需要,要么你是在项目的顶层文件夹( src你的情况),或为顶层文件夹是Python的搜索路径。 需要你在一个特定的文件夹是尴尬,和你说,你不希望出现这种情况。 获取src入搜索路径是那么我们的目标。

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

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



Answer 3:

我想这样做是为了避免设置PYTHONPATH摆在首位

还有其他地方,你可以挂接到Python的sys.path初始化,使用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模块的当前选择坚持为脚本。

有可能是另一种选择,但是这取决于你想实现什么。



文章来源: Proper initialization of sys.path when main script is in a submodule