一、什么是whl文件?
whl是一种预编译的二进制包文件,它主要用于安装python库。简单来讲whl就是一种已经编译好的python库文件。我们可以使用whl包来安装python库。
二、我们为什么需要使用whl文件来安装python库?
有的小伙伴可能会疑惑,我们安装python库时使用“pip install [库名]”来安装一个python库,这样可以直接借助网络将这个库的包拉下来并且将这个库的依赖项也一并拉取下来。拉取下来以后pip还会帮我们解决这些库的依赖问题,这样的方法明明很方便,为什么我们还需要使用whl包来安装python库?其实,使用whl一般用于一些很特殊的情况,比如在公司的内部服务器中,这些服务器是不允许连接网络的;亦或是我们使用pip命令安装库时,即使换源了,但是下载依旧很慢。遇到这些情况时,我们大概率都是把要安装的包下载下来再安装。
三、我们应该去哪儿下载whl包?
我们可以去到python官方的第三方软件库“pypi”,它是一个中央存储库,开发者可以在这里上传他们的软件包,而其他开发者可以下载并使用这些软件包。所以,我们接下来会演示如何在pypi中下载一个库并且解决它的依赖关系最后安装它。
四、下载whl包
我们可以直接在浏览器中搜索“pypi”。
如图所示,我们搜索出来的第一个就是“pypi”的官方网站了。如果你像我这样搜索没有搜索到“pypi”的官方网站,也可以输入下面的网址打开。
pypi官方网址:PyPI · The Python Package Index
打开官网以后我们可以看到中间有一个很大的搜索框。
我们直接在搜索框中搜索我们想要的python包即可。这里我使用“pygame”包举例。我们在搜索框中输入“pygame”并且回车。
回车以后应该就能看到下面这个界面了。
我们可以看到这里有非常多的python包,我们点击第一个即可。
点击以后,来到如下界面,我们后面来看看这个界面。
我们可以看到这个页面的左边有三个大的选项,下面我们来讲讲这些选项的作用。
首先第一个选项是项目描述,这里会对整个包有一个大致的描述包括依赖python的版本或者安装方式,不同的python包他们的描述也不一样。
第二个选项是这个包的历史版本,我们可以点击进去下载这个包的历史版本。
第三个选项是文件下载,这里包含这个包在不同架构,不同操作系统,不同python的各个版本。我们会重点查看这个选项,教大家怎么去分辨一个包是不是适合你的,如果一个包与你的操作系统或者是架构,亦或是python不兼容,那么就会出现安装失败的情况。
我们下面拿一个包来举例。
pygame-2.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
首先是pygame:这个是我们要安装的这个包的名称。
2.6.0:这是我们要安装这个包的版本号。
pp39:通常表示这个whl包是pypy(一个Python解释器的替代实现)的python3.9版本构建的。你除了可能可以看到pp39以外,你还有可能看到cp39,这就表示这个包是Cpython(python的官方实现)的python3.9版本构建的。大部分的python包都会给出pp和cp两种,这两种类型的包除了在运行速度上有区别。在使用方式上,这两种形式的包都是一样的。
pypy39:这里作为一个再次强调它使用了pypy的python3.9来构建的包。这里值得注意的是,这个包用哪一个python构建就要用哪个python来运行。比如这里我们就需要python3.9
manylinux_2_17_x86_64:这表明这个whl包是针对“manylinux 2.17”兼容性的,它是GNU/Linux操作系统的标准化的二进制兼容性目标,旨在与多种Linux发行版兼容。x86_64
表示这个包是为64位x86架构编译的。当然,如果你是新手,那么你只需要知道这个包是在linux系统使用的就行了。
这就是这个包名的大概信息了,我们可以来整理一下,这个包的名字叫pygame,它的版本为2.6.0,基于pypy39构建的linux x86_64版本。
下面我们再来看一个包名。
pygame-2.6.0-cp312-cp312-win32.whl
简单的分析就可以得出,这个包的名字是pygame,它的版本是2.6.0,基于Cpython3.12构建的windows32位版本。
我们现在已经了解到了这些包名的含义,那么我们就要根据我们对应的操作系统,架构和python版本来下载对应的包,我们可以使用下面的命令来查看python的版本。
python --version
输入命令回车以后就会输出python的版本了。我这里的python是3.8,那么我肯定是要使用pp38或者cp38类型的包。
我们可以使用下面这条命令来查看自己的系统架构:
$env:PROCESSOR_ARCHITECTURE
这里可以看到我的系统架构是AMD64,也就是64位系统。我们肯定要选择x86_64版本的包。
经过筛选,我们可以看到,这个包是完美适合我计算机环境的。
我们点击这个包的包名浏览器应该就会开始下载了。
我们将这个包放到一个我们能找到的地方。
五、whl包的安装
我们在powershell中将路径切换到这个放有whl包的文件夹,我们切换到这个文件夹以后可以使用“ls”命令查看这个目录下的文件,如果你使用“ls”没有看到这个文件,哪怕出现了再多的文件都意味着你的路径错误了。请将下载的文件放到一个你能找到的位置再使用powershell把路径切换过去,或者使用绝对路径。
现在有了这个文件我们就可以开始安装了。
我们可以先使用下面这个查看安装的包的指令来查看我们已经安装的包。
pip list
我们可以使用下面的命令来安装一个whl包:
pip install [包名]
如果你被提示pip命令找不到,你需要先安装pip命令。但是现在应该都不会出现这种情况,在python较新的版本中,python被安装时就附带了pip。
我这里的包名是“pygame-2.6.0-cp38-cp38-win_amd64.whl”所以我会使用“pip install pygame-2.6.0-cp38-cp38-win_amd64.whl”来安装这个包。值得注意的是,这里因为我的包就在这个目录下我才直接输入了包名,如果这个包不在这个目录,我就应该输入别的路径。
输入命令以后回车,就可以得到以下输出:
我们看到下面这样的输出就表示这个库已经安装成功了。我们再次使用“pip list ”来查看我们已经安装的包。
我们可以发现,刚刚安装的包已经出现在这里面了。
至此我们的whl包已经安装完成。当然,不是所有的whl包都能直接安装,它们其中的有些依赖了别的包,别的包又依赖了另外的包,依赖关系非常复杂,如果不先安装好一个包依赖的包,那这个包就无法安装,下面我们将来讲一下怎么解决python包之间的依赖关系。
六、在解决依赖关系后来安装whl包
我们现在先来看在线状态pip包管理器是怎么解决依赖关系的。在在线状态下,如果我们使用pip安装包,不管这个包是被下载好的还是说这个包在网络上,我们希望pip自动来安装。pip都是会去网络上下载包。如果你把一个whl包下载到了本地,pip会在安装它时查看它依赖的包,如果它依赖了没有安装的包,pip就会去网络上下载对应的whl文件并且安装它,pip会一直重复这个过程,缺少什么就安装什么,直到把你想要安装的python包给安装好。
首先强调,我们这里讲纯离线的环境,就是完全没有网络的情况下,也就是说pip不能自动去拉取包的情况下我们应该怎么安装whl包。我们来看一个错误复现,我使用“pip install PyQt5-5.15.11-cp38-abi3-win_amd64.whl”来安装名为pyQt的包,但是我出现了下面的错误。
我们可以看到前面的黄字和后面的白字大概都是在提示我们网络有问题,还记得pip解决依赖关系的办法吗?是的,pip找不到依赖包时,它会先去网络上找。但是现在我已经处于纯离线环境了,根本不存在网络,所有pip根本就不能去下载包,也就报出了下面红色的错误。我们将其拷贝过来看。
ERROR: Could not find a version that satisfies the requirement PyQt5-sip<13,>=12.15 (from pyqt5) (from versions: none)
ERROR: No matching distribution found for PyQt5-sip<13,>=12.15
它的大概意思就是找不到PyQt5-sip这个库的大于或者等于12.15的版本。
遇到这种情况我们应该怎么办呢?当然是安装它需要的库啦。但是我们现在还是处于离线的环境,所以,我们还是要使用whl离线包来安装pyQt所需要的库。
但是现在还有一个问题就是,一个whl文件它可能不会只依赖一个包,我们应该怎么去查看whl的所有依赖的包呢。其实也很简单。whl文件本质上就是一个压缩文件,我们只需要把后缀名改成zip再解压就行了。如图:
我们将其解压,就可以看到下面的这几个文件夹了。
然后我们再进入文件夹名字带“info”的文件夹
进入以后我们使用记事本打开文件夹中的“METADATA”文件。
我们可以看到这个文件中有几行“Requires-Dist”,这些就是这个whl文件依赖的包了,我们现在看一下,现在这个名为pyQt的包依赖了“PyQt5-sip (>=12.15, <13)”,“PyQt5-Qt5 (>=5.15.2, <5.16.0)”这两个包,我们现在去下载这两个包。
我们下载了这两个包以后,使用同样的方法查看了它们所需的依赖。
我们可以看到它们并不依赖别的什么库,所以我们可以直接开始安装。
可以看到我们这两个包已经安装成功了,最后我们来安装pyQt。
至此,我们已经解决了所有的依赖关系。当然作为演示,我们使用的只是一个依赖关系较少的库。在实际的运用中某些库的依赖关系要复杂得多。
七、结语
不管一个python库依赖关系再复杂,它都拥有“METADATA”,让我们有迹可循。人生为什么不是这样?当我们在大学迷茫的时候,为什么不尝试去找找我们生活中的“METADATA”呢?