背景
随着构建的Python项目越来越大,回顾以往项目代码,有些结构比较混乱,最近做的RAG项目流程较多,这里结合一些优秀开源项目,梳理一下项目架构,并对本次项目中出现的一些疑问做记录。
这里的参考项目偏AI方向, 主要参考如下2个项目架构:
24k star的国内开源RAG项目 Langchain-Chatchat
48k star的国外开源项目 privateGPT
组织架构
从上述两个项目中抽取其核心架构,项目构建的基础架构如下所示,其中,加粗的代表文件夹
own_project
├── configs
├── docs
├── main_folder
├── tests
├── scrips
├── CHANGELOG.md
├── README.md
├── requirements.txt
├── startup.py
├── LICENSE
整体来看,可以总结如下几点注意事项:
- 项目详情可以写在README.md中。
- 项目更新日志可以写在CHANGELOG.md中(项目小的话,可以在README中写关键更新,不需要特意维护更新详情)。
- 如果项目大,可以在docs中维护文档(privateGPT专门维护了一个docs的网页,使用Fern维护)。
- 在configs中写全部的配置。
- 主题代码文件可以在own_project新建一个main_folder(privateGPT是这种方式),也可以直接在own_project下写项目主要代码(chatchat是这种方式)。
- 根目录下包括项目的入口文件
startup.py
或者run.sh
- 运行的脚本文件写在scrips文件夹中
init.py文件详解
由于整个项目层级结构复杂,在完成项目的架构搭建后, 需要使用__init__.py对引入的包做简化处理。这里简单介绍下使用方法(这里忽略python2中的用法)
通俗来说,init.py 可以将文件封装成包,将多个文件合并到一个逻辑命名空间。
当在文件夹里创建__init__.py文件能够使该文件夹变成一个Module,当这个文件夹(Module)被import时,会先执行__init__.py里的代码。
__ init__.py里面一般写该文件夹Module里的子Module的需要具体import的属性,函数,类等。
假设我们的项目只有最简单的configs文件夹及project文件夹, 项目结构如下所示:
project
├── configs
**│ ├── **__init__.py
**│ ├── **conf.py
**├── run.py
conf.py中定义一个变量**TOP_K**
,**现在我们想在run.py
中要引用conf.py中的变量
如果没有__ init__.py,当我们要导入一个py文件中的属性、函数、变量、类……时,需要使用如下方式:
1 | from configs.conf import TOPK |
而 **不能 **采用更简洁的方式导入,例如:
1 | import configs |
这是因为configs是一个包(package),而不是一个模块(module)。包和模块的区别为:
模块(Module):python中一个**.py文件就是一个模块。模块是一个包含Python代码的文件,它可以定义函数、类和变量。其他Python程序可以通过import**语句导入模块,并使用模块中定义的内容。
包(Package):包是一个包含多个模块的目录(文件夹),是一种更高级别的组织方式,用于组织多个相关的模块。
通过使用包,可以更好地组织和管理项目中的代码,避免模块名称冲突,并提高代码的可维护性和可重用性。
如果在configs下的__init__.py文件中写入
1 | from .basic import TOP_K |
则在run.py
中便可以使用如下方式直接导入变量
1 | from configs import TOP_K |
所以在__Init__.py文件中通常写该文件夹Module里的子Module的需要具体import的属性,函数,类等
from 【.子Module文件名】import 子Module里的属性,函数,类等
测试函数
python的测试函数一般写在tests文件夹下,与代码目录在同一父路径下,这里需要使用python -m 指令运行tests文件夹下的测试文件。
python -m tests.test:这种方式会以模块的形式运行指定的测试模块, 确保 Python 解释器能够正确地找到测试模块,并且可以避免由于当前工作目录不同而导致的模块导入错误。
极简项目架构如下所示:
project
├── configs
**│ ├── **init.py
**│ ├── **conf.py
├── tests
**│ ├── **test.py
├── src
**│ ├── **show_def.py
我们需要在tests/test.py中对src/show_def.py中的函数做测试。
show_def.py内容如下:
1 | from configs import TOP_K |
test.py内容如下:
1 | from src import show_def |
在shell中运行python -m tests.test,最终的输出结果为: src show_def func 5
可以看到,在show_def中成功导入了configs内的变量,且在test.py中成功对函数simple进行了测试。