Python封装应用程序的最佳项目结构是什么?
转载来源于stackoverflow:https://stackoverflow.com/questions/193161/what-is-the-best-project-structure-for-a-python-application
和http://www.cnblogs.com/alex3714/articles/5765046.html#3719169
开发一个终端用户桌面应用(非网页),最佳的项目文件夹层次结构是怎样的?
理想的项目文件夹层次结构的主要特征是易于维护,友好的ide,合适的源代码的控制分支/合并,轻松生成安装包。
注意点:
- Where do you put the source?
- Where do you put application startup scripts?
- Where do you put the IDE project cruft?
- Where do you put the unit/acceptance tests?
- Where do you put non-Python data such as config files?
- Where do you put non-Python sources such as C++ for pyd/so binary extension modules?
Project/ # When you do releases, you should include a version number suffix: Twisted-2.5.
|-- bin/ 存放项目的一些可执行文件,当然你可以起名script/
之类的也行。
| |-- project 不要在它们中添加任何代码,除非对项目中其他地方定义的一个主函数调用和调用。
|
|-- project/ 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。
| |-- test/ (2) 其子目录tests/
存放单元测试代码;
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py (3) 程序的入口最好命名为main.py
。
| |
|-- docs/ 存放一些文档。
| |-- conf.py
| |-- abc.rst
|
|-- setup.py 安装、部署、打包的脚本。
|-- requirements 存放软件依赖的外部Python包列表
|-- README 项目说明文件。
Do:
- name the directory something related to your project. For example, if your project is named "Twisted", name the top-level directory for its source files Twisted. When you do releases, you should include a version number suffix: Twisted-2.5.
- create a directory Twisted/bin and put your executables there, if you have any. Don't give them a .py extension, even if they are Python source files. Don't put any code in them except an import of and call to a main function defined somewhere else in your projects. (Slight wrinkle: since on Windows, the interpreter is selected by the file extension, your Windows users actually do want the .py extension. So, when you package for Windows, you may want to add it. Unfortunately there's no easy distutils trick that I know of to automate this process. Considering that on POSIX the .py extension is a only a wart, whereas on Windows the lack is an actual bug, if your userbase includes Windows users, you may want to opt to just have the .py extension everywhere.)
- If your project is expressable as a single Python source file, then put it into the directory and name it something related to your project. For example, Twisted/twisted.py. If you need multiple source files, create a package instead (Twisted/twisted/, with an empty Twisted/twisted/__init__.py) and place your source files in it. For example, Twisted/twisted/internet.py.
- put your unit tests in a sub-package of your package (note - this means that the single Python source file option above was a trick - you always need at least one other file for your unit tests). For example, Twisted/twisted/test/. Of course, make it a package with Twisted/twisted/test/__init__.py. Place tests in files like Twisted/twisted/test/test_internet.py.
- add Twisted/README and Twisted/setup.py to explain and install your software, respectively, if you're feeling nice.
Don't:
- put your source in a directory called src or lib. This makes it hard to run without installing.不要将源代码的目录命名为src或lib。这会导致安装困难。
- put your tests outside of your Python package. This makes it hard to run the tests against an installed version.不要将tests文件放在python包之外,否则会导致在安装的版本上运行测试出现问题。
- create a package that only has a __init__.py and then put all your code into __init__.py. Just make a module instead of a package, it's simpler.不要创建一个只有一个__init__的包,并且将所有的代码都放在这个包里面。而是应该创建一个模块而不是包,相对于创建包,创建模块管理更加简单。
- try to come up with magical hacks to make Python able to import your module or package without having the user add the directory containing it to their import path (either via PYTHONPATH or some other mechanism). You will not correctly handle all cases and users will get angry at you when your software doesn't work in their environment. 尝试想一些方法使得Python能够不需要用户设置添加目录到导入环境中,通过Python路径或其他机制自动的导入项目中的模块和包。如果你的软件不能正确地处理所有的情况,当你的软件在他们的环境中不工作时,用户会非常生气。
setup.py
一般来说,用setup.py
来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。
setup.py
可以将这些事情自动化起来,提高效率、减少出错的概率。"复杂的东西自动化,能自动化的东西一定要自动化。"是一个非常好的习惯。
setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。学习技术的方式就是看他人是怎么用的,可以参考一下Python的一个Web框架,flask是如何写的: setup.py
当然,简单点自己写个安装脚本(deploy.sh
)替代setup.py
也未尝不可。
requirements.txt
这个文件存在的目的是:
- 方便开发者维护软件的包依赖。将开发过程中新增的包添加进这个列表中,避免在
setup.py
安装依赖时漏掉软件包。 - 方便读者明确项目使用了哪些Python包。
这个文件的格式是每一行包含一个包依赖的说明,通常是flask>=0.10
这种格式,要求是这个格式能被pip
识别,这样就可以简单的通过 pip install -r requirements.txt
来把所有Python包依赖都装好了。具体格式说明: 点这里。
README 项目说明文件。
它需要说明以下几个事项:
- 软件定位,软件的基本功能。
- 运行代码的方法: 安装环境、启动命令等。
- 简要的使用说明。
- 代码目录结构说明,更详细点可以说明软件的基本原理。
- 常见问题说明。
关于配置文件的使用方法
注意,在上面的目录结构中,没有将conf.py
放在源码目录下,而是放在docs/
目录下。
很多项目对配置文件的使用做法是:
- 配置文件写在一个或多个python文件中,比如此处的conf.py。
- 项目中哪个模块用到这个配置文件就直接通过
import conf
这种形式来在代码中使用配置。
这种做法我不太赞同:
- 这让单元测试变得困难(因为模块内部依赖了外部配置)
- 另一方面配置文件作为用户控制程序的接口,应当可以由用户自由指定该文件的路径。
- 程序组件可复用性太差,因为这种贯穿所有模块的代码硬编码方式,使得大部分模块都依赖
conf.py
这个文件。
所以,我认为配置的使用,更好的方式是,
- 模块的配置都是可以灵活配置的,不受外部配置文件的影响。
- 程序的配置也是可以灵活控制的。
能够佐证这个思想的是,用过nginx和mysql的同学都知道,nginx、mysql这些程序都可以自由的指定用户配置。
所以,不应当在代码中直接import conf
来使用配置文件。上面目录结构中的conf.py
,是给出的一个配置样例,不是在写死在程序中直接引用的配置文件。可以通过给main.py
启动参数指定配置路径的方式来让程序读取配置内容。当然,这里的conf.py
你可以换个类似的名字,比如settings.py
。或者你也可以使用其他格式的内容来编写配置文件,比如settings.yaml
之类的。