如果你写过Go 或者 Rust,你会发现它们的项目结构特别的规整,就跟带了强迫症一样
但是Python却恰恰相反,这玩意从诞生之初压根就没考虑过工程结构这事
所以早期的Python管理相当放飞自我,好在一方面官方的pep规范一直在努力的打补丁,另一方面许多流行的库的项目结构都长得差不多,好歹算是有个很好的参考
妙妙小工具——Conda
现在的Python工程管理分为了两大流派,第一大派则是Conda宇宙
Conda本身是一个商业软件,但是大家用的最多的是它的免费版本,MiniConda和最近很火的pixi都属于这个生态
但是Conda这个体系从根上来说,和官方的Python八竿子打不着一块去
有着自己的配置文件,自己的软件仓库,甚至连Python解释器都是自己编译的,更关键的是Conda不止是支持Python服务,也支持GO,Rust,C++等各种各样的语言,只是Conda刚好选择了Python作为最主要的交互语言而已
这样做的好处是,Conda从设计之初就想的很周全,把多语言支持,依赖管理,虚拟环境等令人头大的问题,用一套统一的方案全给解决了,相比之下官方的Python体系在早期就是一个烂摊子
同时,Conda的问题也不少,Conda想成为一个跨语言的包管理器,带来的问题就是臃肿不堪,速度堪忧,主打一个大炮打蚊子
频道冲突、封闭生态等问题也是层出不穷
在轻量级、符合标准的现代工具如 uv 和 pixi 崛起的今天,Conda的架构显得愈发陈旧和过时
不过本文章的重点并不在这,我们先点到为止,之后会单独开一篇文章来讲解Conda这一工具(会出的!)
Python官方体系
注意!以下都是些过时的写法,了解一下来龙去脉就好,不推荐在真实项目中使用(重点)
目前管理依赖建议使用UV这个包管理工具,如果想了解这个工具可以移步至这篇文章,链接跳转
我们先从一个例子开始,假如我们手里有个项目
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello'
if __name__ == '__main__':
app.run(debug = True)
目录里只有一个代码文件main.py(如图),这个项目非常简单,就是个用Flask写的hello world
在一个新的环境里,Flask这个库通常是没有安装的,直接运行肯定会报错
这好办,我们的第一反应肯定是用pip来安装:
pip3 install flask
运行pip后:

好耶,程序能够成功运行力,可喜可贺
但是请注意,用这种方式安装会放入一个全局环境之中

这样在开发过程中会带来俩个很棘手的问题
1.版本冲突
比如main.py使用的flask是3.1.1版本,而old.py可能只兼容3.0版
那么我们因为新项目而全局升级了flask库,旧项目就可能因为版本不匹配而无法运行
2.复杂的依赖关系(也就是依赖地狱)

一个库通常会依赖其他几个库,其他的库又有各自的依赖,这样一层层嵌套下来,就会引发更多的版本冲突
而虚拟环境就是为了解决这个问题而设计出来的
python3 -m venv .venv
输入这个代码就能生成一个名叫.venv的虚拟环境
执行完后 你的目录里就会多一个名为.venv的目录

名字是可以随便取的,但我还是推荐就叫.venv,这样你的IDE能够自动检测到这个名字
如果没有使用IDE,就用以下命令来激活这个环境
source .venv/bin/activate
现在我们有了虚拟环境,项目之间的依赖总算被隔离开了
这样应该就没问题了………吧?
依赖管理
自己运行到是没啥问题了,那么我们要怎么把项目的依赖分享给别人呢
总不能让人执行一大堆pip install命令吧,太容易出错了,还不专业:(
为了解决这种问题,早期最主流的做法是用pip freeze命令,这样就可以列出所以已经安装好的包和版本号

并用重定向符把这些内容输出到一个文件里,这个文件名可以随便取,但一般我们会叫做requirements.txt

对方只需要在自己的虚拟环境里执行:
pip install -r requirements.txt
pip就会读取这个文件,并把里面的依赖全部安装一遍,这种安装方式非常直观,现在依然可以在大量开源项目中看到requirements.txt的身影
这样做会有一个很大的缺陷,那就是分不清楚项目需要的直接依赖,和这些直接依赖引入的间接依赖
在项目中,明明我们只有Flask这一个直接依赖,requirements.里却又7个包,如果说项目很简单,这问题不大,只要项目变得复杂,那就有得玩了
更麻烦的是,在卸载包的时候,根本处理不好这种依赖关系
卸载Flask:
pip uninstall flask
然后再重新生成requirements文件

会发现pip只会移除Flask本身,Flask的依赖仍然存在,这些依赖会留在环境里面,变成没人管的孤儿依赖
现代Python项目的标准解决方案是使用pyproject.toml
评论(0)
暂无评论