Python项目脚本中处理路径和可执行文件的最佳实践(如Django的manage.py或fabric)
我在不同的项目上做了很多工作(我是个科学家),这些项目的文件夹结构都差不多。例如:
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 个回答
你可以通过创建一个小的包来轻松实现你的目标,这个包可以包含你每一个项目。使用paste scripts来创建一个简单的项目框架。要让它可以执行,只需通过setup.py develop
来安装它。现在,你的脚本只需要导入这个包的入口点并执行它就可以了。
在一个你在当前终端中加载(而不是直接运行)的脚本里,你设置了一些环境变量:
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)
这样你就不需要再改动这些了,只需编辑模块代码,同时也能享受到字节码缓存的好处。
保持执行在顶层
一般来说,尽量把你的运行时保持在顶层。这会让你的导入变得简单很多。
如果你需要频繁使用相对导入,说明可能有更好的方法。
修改路径
其他人提到过 PYTHONPATH
。这是在你的命令行中永久性修改路径的好方法。
如果你不想或不能直接修改 PYTHONPATH
,你可以使用 sys.path
来摆脱相对导入的麻烦。
使用 sys.path.append
sys.path
其实就是一个内部的列表。你可以往里面添加内容,来扩展你的路径。
比如我在 /bin
目录下,而有一个库 markdown
在 lib/
里。你可以用 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 帖子,获取更具体的例子。