Python 软件项目文件结构组织

作者 Marlous 日期 2019-04-03
Python 软件项目文件结构组织

参考:
1、 有趣的Python爬虫和Python数据分析小项目
2、 python基础6–目录结构
3、 开篇python–明白python文件如何组织,理解建立源文件
4、 Open Sourcing a Python Project the Right Way
5、 python模块和包,项目结构
6、 Python Guide 系列 2.1:结构化你的项目
7、 requests 库项目参考
8、 Requests源码阅读
9、 我的项目:weibo-friends-analysis

PyCharm 里,右键点击文件夹(存放源代码的文件夹),Make Directory As -> Sources Root

一 基本概念

  1. 包、模块、类:
  • 包:
    文件夹中包含多个 .py 文件,一个 __init__.py 文件(内容可以为空)。

  • 模块:
    模块对应的是一个.py 文件。

  • 类:
    包含函数、变量。类中有属性和方法。一个对象就是一个类的实例。

  1. import 优先级:
  • 当前文件目录
  • 环境变量 PYTHONPATH
  • sys.path(list 类型)
  1. 关于主函数代码:
  • 没有缩进的代码(非函数定义和类定义),都会在载入时自动执行,这些代码,可以认为是 Python 的 main 函数。
  • 为了区分主执行文件还是被调用的文件,Python 引入了一个变量 __name__,当文件是被调用时,__name__ 的值为模块名,当文件被执行时,__name____main__
  • 当我们在命令行运行模块文件时,Python 解释器把一个特殊变量 __name__ 置为 __main__,而如果在其他地方导入该模块时,if 判断将失败,因此,这种 if 测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。
    1
    2
    if __name__ == '__main__' :
    test()
  1. __init__.py 文件:

    1
    2
    3
    4
    5
    __all__ = ['模块名'] # 定义该包下哪些模块可以被其它模块引用。

    import sys # 批量导入模块
    import io
    import datetime
  2. 一些模块内置变量:

    1
    2
    3
    4
    __name__ 表示命名空间
    __package__ 表示包名称
    __doc__ 表示模块注释,文档写在两行双引号中间
    __file__ 表示模块路径
  3. 不同作用域、用途的变量:

  • __xxx__ 是特殊变量,可以被直接引用。
  • _xxx 和 __xxx 这样的函数或变量就是非公开的(private),不应该被直接引用。外部不需要引用的函数全部定义成 private,只有外部需要引用的函数才定义为 public。

二 文件组织

  1. 实例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    weibo-friends-analysis/
    |-- bin/ 或 Scripts/
    | |-- ...
    |
    |-- src/
    | |-- tests/
    | | |-- __init__.py
    | | |-- test_main.py
    | |
    | |-- one/
    | | |-- __init__.py
    | | |-- one.py
    | |
    | |-- __init__.py
    | |-- main.py
    | |-- fun.py
    | |-- setting.py
    |
    |-- docs/
    | |-- abc.rst
    | |-- conf.py
    |
    |-- setup.py
    |-- requirements.txt
    |-- README
  • setting.py:
    包含 setting 类,这个类只包含方法 __init__(),用来初始化一些东西。

  • requirements.txt:
    此文件列出项目所需的任何第三方依赖项。它让其他人知道为了处理项目需要哪些库。简单来说,它是一个 pip 安装要求列表。

  • setup.py:
    安装、部署、打包的脚本。在 setup.py 文件中写明依赖的库和版本,以便到目标机器上能够使用 python setup.py install 安装。

  • scripts/
    项目用到的各种脚本。

  • docs/
    项目文档,一般来说里面还包含 config.py。

  • etc/
    用来存放配置文件的样例。

  • tools/
    用来存放与工具有关的shell脚本。

  • bin/
    用来存放将被setup.py安装的二进制脚本。

  • data/
    用来存放其他类型的文件,如媒体文件。

  • 如果是发行自己的模块,顶层目录还需要下面三个文件:
    setup.cfg: 包含 setup.py 默认命令选项的 ini 文件。/ LICENSE.txt 项目许可说明文件。如果需要使用 setuptools 等工具进打包发行,那么需要一个许可文件。/ MANIFEST.in:装箱清单文件,当需要打包源码中不自动包含的附加文件时使用。

  1. 调用方法:
  • 主程序与模块程序在同一目录:
    main.py 中直接使用 import funfrom fun import *

  • 主程序使用子目录下的模块:
    main.py 中直接使用 import tests.test_mainfrom tests.test_main import *

  • 子模块使用上级 / 其它同级包中模块:
    test_main.py 使用 main.py 和 one.py,在 test_main.py 中直接导入使用,然后在 tests/ 文件夹中执行 test_main.py。/ 使用同级包中的模块可以直接 import 模块名(可以忽略 IDE 的警告)。

    1
    2
    3
    4
    import sys
    sys.path.append("..")
    import src.main
    import one.one
  1. 小结:
    导入模块关键是能够根据 sys.path 环境变量的值,找到具体模块的路径。

  2. 主函数 main.py 调用其它脚本方法:

  • 主函数中 os.system('python ./自己的包名/XXX.py'),如果是同级目录的话 os.system('XXX.py'),最好是先拼出绝对路径再执行 this_file_path = os.path.abspath(__file__)[:-7] os.system(this_file_path + 'modules/help.py');主函数中用 from 自己的包名 import 模块名

  • 包中的模块使用同级其它模块 from 自己的包名 import 模块名

  • 使用 from 这种方式导入,直接代码中使用 模块名.其中的函数 就行了,使用更简洁。

三 单个文件结构

单个文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python        可以让这个py文件直接在Unix/Linux/Mac上运行
# -*- coding: utf-8 -*- 使用标准UTF-8编码;

' a test module ' #表示模块的文档注释

__author__ = 'Michael Liao' #作者名

import sys #导入其他模块
import cStringIO as StringIO #导入其他模块,并使用as命名别名

def test():
return True

'''
当我们在命令行运行模块文件时,Python解释器把一个特殊变量__name__置为__main__,
而如果在其他地方导入该hello模块时,if判断将失败,
因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,
最常见的就是运行测试。
'''
if __name__=='__main__':
test()
  • 在每个文件模块里放置了一个函数,可以放置许多函数;也可以在这些文件里定义 Python 的类,然后为这些类建一个包。

  • 多个文件相互调用组织:
    将主逻辑定义成函数写在 main.py 中并在其中运行(类似面向过程)。主函数模块用到的子模块、包在前面导入;剩下的类、函数等全部拆成模块、包,被 main.py 中的主逻辑函数调用(面向过程、面向对象)。