# 从日常开发说起setup.cfg到底帮了我们什么这些年见过不少Python项目有的简洁利落有的混乱得让人头疼。一个项目能不能长久维护很多时候从它的配置文件就能看出来。今天聊聊setup.cfg这东西看起来不起眼但用好了能让项目清爽不少。它是什么setup.cfg本质上是一个INI格式的配置文件放在项目根目录。很多人第一次见到它是在读别人项目代码的时候看到文件夹里躺着setup.py、setup.cfg、pyproject.toml心里犯嘀咕这些文件到底什么关系打个比方setup.py就像一个保姆什么活都干——装包、配参数、跑测试。而setup.cfg是把这个保姆的工作清单单独列出来让setup.py只负责执行。这样分工明确谁该干什么一目了然。INI格式其实特别简单就是各种[section]下面写key value。比如[metadata] name myproject version 1.0.0这跟你平时用的配置文件没啥两样所以上手成本几乎为零。它能做什么说几个实际场景吧。有个同事负责的项目setup.py里写了将近两百行代码各种判断逻辑、动态获取版本号、根据环境变量决定依赖包版本。每次改版本号都得小心翼翼生怕触动了哪根神经。用setup.cfg之后这些配置项被剥离出来变成干净的数据。比如版本号直接在metadata里写着[metadata] version 1.2.3依赖包列表放到options里面[options] install_requires requests2.20 flask1.1这还不是最妙的。setup.cfg能做的更多是那些枯燥但重要的事情。比如你有很多测试工具需要配置pytest、flake8、coverage传统做法是每个工具写一个配置文件项目根目录塞满了.coveragerc、.pylintrc、setup.cfg、tox.ini。但如果你愿意setup.cfg可以统一管理这些工具的配置只要在tool:前缀后面写清楚就行[tool:pytest] testpaths tests [flake8] max-line-length 120怎么使用实际用起来分几步走。第一步创建setup.cfg按规范把元数据和参数写好。有个小细节容易被忽略setup.cfg的编码一定要是UTF-8尤其是当你的项目描述里包含中文或者特殊字符时。第二步把setup.py瘦身。理想情况下setup.py只要这么几行fromsetuptoolsimportsetupif__name____main__:setup()这听起来有点偷懒但确实是最简洁的做法。如果setup.py里不得不保留一些逻辑比如从环境变量读取某些值至少要保证这些逻辑不会跑偏。第三步善用pbr或者setuptools-scm这类工具。比如我要让版本号跟着git tag走只需要在setup.cfg里配置[options] setup_requires setuptools-scm然后在setup.py里加上use_scm_versionTrue这样每次git打tag后包版本自动更新再也不用手动改数字。最佳实践用了这么多年踩过不少坑总结几条经验。第一不要把所有东西都塞进setup.cfg。有些工具虽然支持在setup.cfg里配置但配置项太多会影响可读性。比如pytest的配置几行能写清楚的可以放几十行的还是单独建conftest.py更合理。第二版本管理要严格。特别是依赖包的版本范围不要图省事只写包名不写版本。比如install_requires numpy1.18,2.0 pandas1.0,1.3这样既保证了可用性又避免了意外升级带来的破坏。第三注意setup.cfg和pyproject.toml的关系。现在pyproject.toml越来越流行很多新项目直接用它代替setup.cfg。但如果项目已经用了setup.cfg完全没必要着急迁移。我的做法是新项目直接用pyproject.toml老项目保持setup.cfg等到下次大版本升级再说。第四关于项目描述。很多人喜欢在description里写“这是一个XX项目”之类的话但更好的做法是把详细说明放到long_description里并且从README.md读取[metadata] description 项目简介 long_description file: README.md long_description_content_type text/markdown这样描述和文档能保持一致避免了重复修改。和同类技术对比setup.py是最早的方案功能最全但也最灵活。灵活性是把双刃剑比如有人会在setup.py里写各种动态逻辑导致构建环境稍微不同就出问题。setup.cfg的出现就是为了解决这个痛点它强制你只用配置不要写复杂逻辑。pyproject.toml是后来的继承者用TOML格式代替了INI而且定义了统一的构建系统接口。它能做的事情比setup.cfg更多比如还能配置构建前端build backend。但从易用性角度看setup.cfg的INI格式因为简单对新手更友好。还有个叫setup_requires的东西它允许你在构建时临时安装依赖但最好别常用。因为一旦某个依赖版本不对整个构建就会卡住。说到底工具只是工具关键看项目需求。如果项目简单、团队小setup.py就够了。如果想让构建过程更清晰可预测setup.cfg是个好选择。而pyproject.toml适合那些需要严格控制构建流程的项目。每个人的喜好不同有的团队坚决只用pyproject.toml有的老项目用了setup.cfg好几年也懒得换。我觉得没必要强求统一只要团队内部达成共识就行。毕竟相比于文件格式代码质量和可维护性才是最重要的。