Python 包管理器介绍与 Pypi 入门指南
坑边闲话:闲话
- 知乎原文
- Status: 已搬运,待校对
包管理器(package manager)和项目管理器(project manager)是两种非常重要的开发管理工具,前者可以保证我们对自己的开发环境有完整的掌控能力,后者可以保证我们对手头的项目有十足的把握能力。但是很多开发者,特别是新手,在初次接触这两个名词时不知所措,我分析来分析去,得出一个结论:他们被日益傻瓜化的封装给绑架了,所以他们看不到这两样东西的重要性。那么接下来的几篇文章,我会详细介绍这两种管理器的一般用法和设计理念,以帮助新手入门。
我的目标是希望新手读者看完文章后,能了解包管理系统、项目管理系统的运作原理,不再完全依赖 Visual Studio 等高度封装的 IDE,写出小而精的项目,令系统的硬盘冗余达到最小。
1. 什么是包管理器·
包管理器与包的开发、安装、更新密切相关。如果一个开发环境所具有的包非常少,那么你不需要包管理器。但是很多时候,随着一个系统的发展,各种各样的包也随之出现,手动管理不再可能。比如 Debian 系列的 Linux 的软件包越来越多,社区急需一个可以管理整个系统的管理器,它可以负责安装新的包、更新旧的包,自动解决包的依赖问题。其中,包的依赖关系十分令人头疼,很多时候安装 A 需要先安装 B,而安装 B 需要安装 C 和 D,这令人无法接受,所以理想的包管理器应该能够自动生成依赖的关系树。
我们常见的包管理器有以下的几个:
apt
,这是 Debian 系列 Linux 发行版的系统级的软件管理器Cygwin-setup.exe
,没错,这是 Cygwin 的包管理器,比较愚蠢的一个非命令行软件(可以安装一个脚本,类似 apt)tlmgr
,这是 texlive 的包管理器,管理各种 LaTeX 的宏包Pypi
,或者简称 pip,这是 Python 的包管理器,管理各种 Python 的包,有时候你import
一个库时用不了,系统说你没有安装这个包,那你就需要pip
了;pip
也和 Python 一样,分 2 版本和 3 版本,其分别针对 Python2 和 Python3homebrew
,这是一个在 macOS 上运行的包管理器,可以管理 macOS 的很多包。因为苹果并没有自己的包管理软件
综上,我们可以总结一下,当可用的包很多时,就需要包管理器了。包管理器需要与镜像服务器联系,以解决问题。
- 询问服务器,你有没有我需要的那个包?如果服务器说有,那么你可以下载,然后本地安装;
- 询问服务器我的这个安装包是不是过时了,能否更新?服务器可以对比版本,如果有新版本,就提示你要升级了。
- 一般本地包管理器通过网络与镜像服务器联系,如果镜像服务器在国外,那么很有可能你的连接速度、下载速度非常慢,这个时候我们最好换国内的镜像服务器。某些大型公司,如阿里、腾讯、网易等,会对公众提供免费的镜像,而很多知名的大学,如清华大学、中国科大,也会对外提供镜像服务。
- 以清华 tuna 举例,它不仅仅提供某个领域的镜像服务,而且似乎全领域服务,它提供 Python 镜像、
apt
镜像、tlmgr
镜像,简直无所不包。新手最应该把这个镜像网站的脉络摸清楚。
2. 介绍一下 Pypi·
Pypi 是 Python 的包管理器上游仓库。
如你需要下载一个 numpy,那就需要运行
1 | pip install numpy |
值得注意的是,用 pip 安装 python 包虽然简单,但是也存在一部分历史遗留的问题。比如它对某些包的 metadata 并不能充分获取,而且有时候哪怕充分获取了,也不足以干净利落地管理这些包。鄙人今天花了点时间研究了一下这方面的内容,有两个问题想谈一谈。
-
首先是
pip
的问题,pip
作为一个针对 Python 的包管理器,同apt
、tlmgr
、npm
等包管理器具有相似的功能,比如安装某个包(pip install <PACKAGE>
)查看本管理器所管理的软件有哪些(pip list
),比如搜索镜像服务器中有哪些包(pip search <KEYWORDS>
),比如列出哪些包过时了需要更新一下(pip list --outdated
),再比如升级一下需要更新的某个包(pip install -U <PACKAGE>
)等。这里的pip
指的是pip2
,管理的是 Python2 的包,你可以替换成pip3
,以管理 Python3 的包。 -
你要知道,有些时候你并不能用
pip
管理所有的包。有时候会遇到以下这种问题。不要着急,也不要忽略旧版本直接升级(这有很大害处!)
1 | Cannot uninstall ‘nibabel’. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall. |
3. 清华 Pypi 镜像·
3.1 临时使用清华镜像来安装某个 Python3 的包:·
1 | pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple <PACKAGE> |
注意:
simple
不能少- 是
https
而不是http
3.2 将清华镜像设为默认·
升级 pip
到最新的版本 (>=10.0.0) 后进行配置:
版本升级,并修改 pip
的链接文件中的代码:
1 | pip install -U pip |
把如下三行
1 | from pip import main |
改为如下形式:
1 | from pip import __main__ |
同理改正 pip3
(sudo vim /usr/bin/pip3
)。
最后在命令行里更改 pip
的 configure
文件:
1 | pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple |
如果你的 pip
默认源的网络连接较差,可临时使用清华镜像站来升级 pip
:
1 | pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U |
pip 的利用方式有很多,有很多可选的选项,如列出所有需要更新的 python 包,然后更新某个名为< package_name >
的包,命令如下:
1 | pip3 list --outdated |
如同 tlmgr
管理所有的 texlive 的宏包一样,pip
也可以管理所有的 Python 库,但是并没有内置的「一个命令升级所有 Python 包」的内置选项,在此鄙人介绍一个简单的 bash 命令:
1 | pip3 list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U |
可以把这个命令起一个别名,然后保存在 bashrc 里,以后直接调用 pip3-upgrade-all
就好,如下所示:
1 | alias pip3-upgrade-all='pip3 list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 sudo pip install -U' |
该命令原理如下:我们知道,单纯运行 pip3 list --outdated --format=freeze
并不会得到一个很显然、很干净的结果,但是我们希望可以得到一个字符串,这个字符串含有所有的待升级 Python 包,而且包与包彼此之间用空格分割。但是系统并没有内置命令。好在可以通过 bash 编程做到这一点。
首先把输出通过 pipe 管道传给了 grep
,让 grep
做一下切割,切割完之后,很多不需要的信息就不存在了;然后再把 grep
的输出通过 pipe 管道传给 cut
,做二次切割,-d =
是一个完整的命令,指的是要用等号
作为分隔符号进行列划分,-f
是指现实哪几列,我们的参数是 1
,所以现实第一列。值得注意的是,这里的 -f
是从 1 开始的,而不是编程中常见的 0;cut
切割完的输出已经是我们的理想字符串了,我们把这个终极字符串,通过 xargs
命令传给 pip install --upgrade
(或者 pip install -U
,这个 -U
就是指 --upgrade
)。
如此就完成了 Pypi 的初步教程。注意,在 Linux 系统上,运行 Pypi 可能需要 root 权限,这时候应该使用 sudo pip
来执行你的操作。
接下来的几篇文章我会介绍其他的包管理器、项目管理器的使用方法。