Python项目脚本中处理路径和可执行文件的最佳实践(如Django的manage.py或fabric)

14 投票
3 回答
8670 浏览
提问于 2025-04-17 12:32

我在不同的项目上做了很多工作(我是个科学家),这些项目的文件夹结构都差不多。例如:

project
   /analyses/
   /lib
   /doc
   /results
   /bin

我把各种实用的脚本放在/bin/文件夹里,因为保持整洁是很重要的。不过,我必须把路径写死(比如说 ../../x/y/z),而且我只能在 ./bin/ 目录下运行这些脚本,否则它们就会出问题。

我用过Django,它有一个 /manage.py 文件,可以运行各种Django相关的操作,并且自动处理路径问题。我也用过fabric来运行一些用户自定义的函数。

我想问:我该怎么做类似的事情?最好的方法是什么?我可以很容易地在 /manage.py 中写点东西,把根目录加入到 sys.path 里,但我希望能通过 "./manage.py foo" 来运行 /bin/foo.py。或者说,fabric能否从某个特定的目录调用可执行文件?

总之,我想要一个简单且维护成本低的解决方案。我希望能把一个可执行的脚本或文件放到 ./bin/ 里,而不需要担心路径或导入的问题。

那么,最好的方法是什么呢?

3 个回答

1

你可以通过创建一个小的包来轻松实现你的目标,这个包可以包含你每一个项目。使用paste scripts来创建一个简单的项目框架。要让它可以执行,只需通过setup.py develop来安装它。现在,你的脚本只需要导入这个包的入口点并执行它就可以了。

4

在一个你在当前终端中加载(而不是直接运行)的脚本里,你设置了一些环境变量:

PATH=$PATH:$PROJECTDIR/bin
PYTHONPATH=$PROJECTDIR/lib

接着,你把你的Python模块和包放在项目的./lib目录下。Python会自动把PYTHONPATH这个环境变量添加到sys.path中。

这样,你就可以在终端中运行任何顶层脚本,而不需要指定路径,同时从你的库模块中导入的内容也会在lib目录中查找。

我推荐一些非常简单的顶层脚本,比如:

#!/usr/bin/python

import sys
import mytool

mytool.main(sys.argv)

这样你就不需要再改动这些了,只需编辑模块代码,同时也能享受到字节码缓存的好处。

6

保持执行在顶层

一般来说,尽量把你的运行时保持在顶层。这会让你的导入变得简单很多。

如果你需要频繁使用相对导入,说明可能有更好的方法。

修改路径

其他人提到过 PYTHONPATH。这是在你的命令行中永久性修改路径的好方法。

如果你不想或不能直接修改 PYTHONPATH,你可以使用 sys.path 来摆脱相对导入的麻烦。

使用 sys.path.append

sys.path 其实就是一个内部的列表。你可以往里面添加内容,来扩展你的路径。

比如我在 /bin 目录下,而有一个库 markdownlib/ 里。你可以用 sys.path 添加相对路径来导入你需要的东西。

import sys
sys.path.append('../lib')
import markdown


print markdown.markdown("""

Hello world!
------------

""")

提醒:不要对你的 sys.path 添加过于疯狂。保持结构简单,以免让自己困惑。

过于频繁的导入有时会导致一个 Python 模块需要导入自己,这样执行就会停止!

使用包和 __init__.py

另一个好方法是通过添加 __init__.py 文件来创建 Python 包。__init__.py 会在目录中的其他模块之前加载,所以这是一个在整个目录中添加导入的好地方。这使得它成为添加 sys.path 修改的理想位置。

你甚至不需要在文件中添加任何内容。只需在控制台输入 touch __init__.py 就可以把一个目录变成包。

查看这个 SO 帖子,获取更具体的例子。

撰写回答