PyPI包名的命名规则与pip的兼容性机制——为什么pip install sCIKit.-_LEarN也能成功
前言
最近我在使用pip install命令安装包时,偶然发现在包名中使用下划线和使用连字符都可以成功安装,而且安装的确实是同一个包。这就激发了我的好奇心,难道pip install 命令中下划线和连字符是等效的?于是我就去网上搜索了一下,并整理了相关资料写成这篇博文。
PyPI包名规则
PyPA编写的Python软件打包用户指南 中说明,包名允许包含大小写字符、数字、句点、连字符、下划线这几种符号。但同时制定了一个规则,叫包名规范化。包名规范化主要包含三个规则:
- 规范包名中的大写字母会全部转换为小写字母
- 规范包名中句点(.)连字符(-)下划线(_)会被统一转换为连字符
- 如果存在多个连字符,会转换为1个
因此,实际上以下几种包名是等价的:
- friendly-bard
- Friendly-Bard
- FRIENDLY-BARD
- friendly.bard
- friendly_bard
- friendly--bard
- FrIeNdLy-._.-bArD (尽管很糟糕,但它确实有效)
最终都会转换为规范形式的包名:friendly-bard
pip安装和卸载包的处理方式
在使用pip install <包名>命令安装包时,pip会首先将包名转换为规范包名,之后再去Pypi库查找并安装。因此,假设你要安装scikit-learn这个包,你甚至可以执行pip install sCIKit.-_LEarN,也是可以安装成功的。
同样的,在卸载包时,pip uninstall <包名>命令也一样,大写字符会自动转成小写,其他的连接符会自动转换为连字符。
打印日志细节的不同
不过我发现pip install和pip uninstall在命令执行成功后的打印日志上细节还是有些不同。以用户输入的包名为sCIKit.-_LEarN为例,pip install sCIKit.-_LEarN执行成功后,输出的是:
Successfully installed joblib-1.5.2 sCIKit.-_LEarN-1.6.1 threadpoolctl-3.6.0
可以看到其中输出的包名和用户输入的一致。
但pip uninstall sCIKit.-_LEarN执行成功后,输出的是:
Successfully uninstalled scikit-learn-1.6.1
可以看到其中输出的包名是规范包名。
目前并不清楚pip在安装和卸载时显示的包名有两种行为模式的原因,可能是有意为之。
番外篇:包名和模块名的不同
需要注意的是,pip install的包名和在python代码中使用import导入的相关模块名称并不一定完全一致。
比如常用的机器学习包sklearn,在代码中导入的用法为:from sklearn import *,但安装的命令却是pip install scikit-learn,而不是pip install sklearn。这也是很多新手会踩的一个坑。

浙公网安备 33010602011771号