无需创建__init__.py文件自动调用常见初始化代码
我在我的项目里有两个文件夹:
project/
src/
scripts/
“src”文件夹里放的是我整理好的代码,而“scripts”文件夹里放的是一些临时用的Python脚本。
我希望所有的脚本都能自动把“../src”加到它们的sys.path里,这样它们就能访问“src”文件夹里的模块。实现这个的一个方法是写一个scripts/__init__.py文件,内容是:
scripts/__init__.py:
import sys
sys.path.append("../src")
这样做是有效的,但会有一个不太好的副作用,就是把我所有的脚本都放进了一个叫“scripts”的包里。有没有其他方法可以让我的所有脚本自动调用上面的初始化代码呢?
我可以直接在我的.bashrc文件里编辑PYTHONPATH环境变量,但我希望我的脚本能开箱即用,不需要用户去调整PYTHONPATH。而且,我也不喜欢为了这个项目而做全局的修改。
3 个回答
你可以在项目目录下添加一个叫做 'pathHack.py' 的文件,然后在里面写一些类似下面的内容:
import os
import sys
pkgDir = os.path.dirname(__file__)
sys.path.insert(os.path.join(pkgDir, 'scripts')
接着,在你项目目录下的一个 Python 文件中,先这样写:
import pathHack
现在你就可以直接从 scripts 目录中导入东西,而不需要加上 'scripts.' 前缀。如果这个目录里只有一个文件,并且你不在乎隐藏这些内容的话,你可以把这段代码直接放在需要的地方。
如果你想让你的脚本可以运行(我假设你是从命令行运行),那么它们必须放在某个路径下。
不过,你所尝试的事情听起来有点奇怪。你能给我们一个具体的例子,说明你想要实现什么吗?
即使你有其他的发布计划,还是建议在你的 src
文件夹里准备一个基本的 setup.py
文件。这样,你可以运行 setup.py develop
,让 distutils 在你的默认路径上放一个指向你代码的 链接(这意味着你所做的任何更改都会立即生效,不需要“重新安装”,而且无论你的脚本在哪里,所有模块都会“正常工作”)。这只是一步,但比什么都不做多了一步,所以这取决于这是否比更新 .bashrc
更麻烦。如果你使用 pip,相应的命令是 pip install -e /path/to/src
。
更稳妥的解决方案,特别是如果你打算在多个开发者的机器上共享或版本控制这些脚本,建议在一个受控的虚拟环境中进行开发。实际上,virtualenv 还内置了 自定义启动脚本的支持。你只需要一个 after_install()
钩子来调整 sitecustomize
,运行 pip install -e
,或者在 site-packages 中添加一个普通的 .pth
文件。这个自定义启动脚本可以和其他脚本一起放在你的源代码管理中,每个开发者的设置只需运行一次。你还可以享受到使用 virtualenv 的常规好处(比如明确的依赖版本管理、与系统配置隔离、以及不同机器之间的标准化等)。
如果你 真的 不想有任何设置步骤,并且愿意 只 在“项目”目录内运行这些脚本,那么你可以放一个 __init__.py
文件,如下所示:
project/
src/
some_module.py
scripts/
__init__.py # special "magic"
some_script.py
然后你的文件可以是这样的:
# file: project/src/some_module.py
print("importing %r" % __name__)
def some_function():
print("called some_function() inside %s" % __name__)
--------------------------------------------------------
# file: project/scripts/some_script.py
import some_module
if __name__ == '__main__':
some_module.some_function()
--------------------------------------------------------
# file: project/scripts/__init__.py
import sys
from os.path import dirname, abspath, join
print("doing magic!")
sys.path.insert(0, join(dirname(dirname(abspath(__file__))), 'src'))
接着你需要这样运行你的脚本:
[~/project] $ python -m scripts.some_script
doing magic!
importing 'some_module'
called some_function() inside some_module
注意!这些脚本 只能 在 project/
目录内这样调用:
[~/otherdir] $ python -m scripts.some_script
ImportError: no module named scripts
为了实现这一点,你又得回去编辑 .bashrc
,或者使用上面提到的选项。最后一个选项真的应该作为最后的手段;正如 @Simon 所说,那时候你真的是在和语言作斗争。