boxmoe_header_banner_img

WELCOME TO NEKO'S SCHOLARLY HOUSE

文章导读

Python项目管理杂谈


avatar
neko 2025年12月24日 42

如果你写过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)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码
Neo 桃花源

个人信息

avatar

neko

随着时间的流逝缓慢成长吧

6
文章
0
评论
1
用户

最新评论