根据docs,sys.path
的第一个条目是当前脚本的目录。在以下设置中,我想更改此默认值。想象一下以下目录结构:
src/
core/
stuff/
tools/
tool1.py
tool2.py
gui/
morestuff/
gui.py
脚本tool*.py
和gui.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
答案 0 :(得分:5)
仅正式批准的方式来运行包中的脚本是使用-m
标志。虽然您可以直接运行脚本并尝试在每个脚本中自己进行sys.path
操作,但这可能会非常痛苦。如果在文件夹之间移动脚本,则可能还需要更改重写sys.path
的逻辑以反映新位置。即使您sys.path
正确,显式相对导入也无法正常工作。
现在,使python -m mypackage.mymodule
工作需要您在项目的顶级文件夹(在您的情况下为src
),或者要在Python搜索路径上的顶级文件夹。要求你在一个特定的文件夹是很尴尬的,你已经说过你不想这样。然后将src
纳入搜索路径是我们的目标。
我认为最好的方法是使用PYTHONPATH
环境变量将解释器指向项目的src
文件夹,以便它可以从任何地方找到您的包。
此解决方案设置简单(可以在.profile
,.bashrc
或其他一些等效位置自动设置环境变量),并且适用于任意数量的脚本。如果您移动项目,只需更新您的环境设置,您就可以全部设置,而无需为每个脚本再做任何工作。
答案 1 :(得分:4)
这里有三个基本选项。我在生产环境和个人项目中都经历了这三个方面。在许多方面,他们相互依赖。但是,我的建议是跳到最后一个。
根本问题是您需要./src
目录位于python搜索路径中。这就是python包装的全部内容。
<强> PYTHONPATH 强>
调整python路径的最简单,用户定义的方法是通过环境变量PYTHONPATH
。您可以在运行时设置它,执行以下操作:
PYTHONPATH=/src python src/gui/gui.py
您当然也可以在全球环境中进行设置,因此希望所有需要它的流程都能找到正确的PYTHONPATH
。但是,请记住,你永远会忘记一个。通常在凌晨3点,您的cron
任务最终运行。
网站套件
为了避免需要环境变量,您的选项几乎就是将您的软件包含在源路径中的现有条目中,或者找到一些其他方法来添加新的搜索路径。因此,这可能意味着将src
目录的内容放入/usr/lib/python2.7/site-packages
或系统site-packages
所在的位置。
由于您可能不想在站点包中实际包含代码,因此可以为两个子包创建符号链接。
由于多种原因,这当然不太理想。如果你不小心命名,那么机器上的每个python程序都会暴露于潜在的名称冲突。您将软件公开给计算机上的每个用户。如果python得到更新,你可能会遇到问题。如果添加新的子包,现在必须创建一个新的符号链接。
稍微好一点的方法是在您的站点包中的某处包含.pth
文件。当python遇到这些文件时,它会将内容(应该是目录的名称)添加到搜索路径中。这避免了必须记住为每个新子包添加新符号链接的问题。
virtualenv and packaging
最好的解决方案就是咬紧牙关,做真正的蟒蛇包装。这与像virtualenv and pip这样的强大工具相结合,让你有一个孤立的(或半隔离的)python环境。
在virtualenv下,您可以在项目中使用自定义site-packages
,您可以轻松地将软件安装到其中,从而避免了早期解决方案的所有问题。 virtualenv还可以轻松维护可执行脚本,以便它运行的python环境完全符合您的预期。
一个缺点是你必须编写并维护setup.py
,它将指示pip
(python安装程序)将你的软件包含在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
答案 2 :(得分:1)
我想这样做是为了避免首先设置PYTHONPATH
还有其他地方可以使用site
模块挂钩Python的sys.path
初始化,这是(默认情况下)在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模块添加一些'样板'代码作为脚本运行。
可能还有另一种选择,但这取决于你想要实现的目标。