pip 装包,本质上是从网上取一个 wheel 或源码包,解到当前环境的 site-packages, 再把依赖顺带装齐。 装不上只有四类原因:没网、包名错、缺编译环境、版本互相打架。 前三个都好查,第四个最难——所以要会看依赖树。 这一节的 Demo 把三件事一起查了:90 个已装包、numpy 2.5.2 与 matplotlib 3.11.1 满足要求、 tensorflow 与 keras 没装(本次环境装不了深度学习框架,正文全部改用 numpy 手写)。
上一节装的是解释器,这一节装的是包。 本节末尾那句「装不了 TensorFlow」很重要:第 3、4、5、6 章书里的代码都是 Keras 写的, 这台机器上没有,所以全部改成 numpy 手写等价实现,正文里会标清楚哪段是教材原码。 Anaconda 也在这一节讲,因为它本质上是「一次装几百个包」的另一种方案。
一、pip 装的到底是什么
pip install numpy 做的事:查 PyPI 上 numpy 的可用版本 → 挑一个和当前 Python 版本、
当前系统匹配的 wheel → 下载 → 解压到 Lib\site-packages → 把依赖也装上。
wheel 是预编译好的二进制包(.whl),装了就能用;
没有对应 wheel 时 pip 会下源码包(.tar.gz)当场编译,这时候才需要编译器。
Windows 上「装不上」十次有八次是后者:某个包没给 Windows 的 wheel,
pip 想编译又找不到 Visual C++ 的编译工具,报一大堆红字。
先看 python -m pip install 包名 的最后三行,那里写着到底缺什么。
报「Microsoft Visual C++ 14.0 required」就是缺编译器;
报「Could not find a version」就是没网或包名错。
二、Anaconda 什么时候用
Anaconda 是一个打包好的发行版:Python 加几百个科学计算包(numpy、scipy、matplotlib、pandas、 scikit-learn、Jupyter……),一次装完。 好处是开箱即用,那些在 Windows 上编译麻烦的包,它给的是编好的二进制。 代价是体积大(几个 G),而且它有自己的包管理器 conda。 conda 和 pip 不要混着用在同一环境里。原因是 conda 只认自己装的包,pip 装的它不知道; 两者对依赖的解析逻辑也不同,混着装最容易被搞成一个谁也升不动的环境。 本书的做法:不装 Anaconda,需要什么 pip 装什么。这样环境里有什么一目了然。
三、版本约束与依赖树
numpy==2.5.2 是死锁,numpy>=2.0 是下限,numpy>=1.20,<3 是区间。
写死版本最稳,但也最容易和别人冲突。
依赖树长这样:matplotlib 要求 contourpy>=1.0.1、cycler>=0.10、fonttools>=4.28.2、
kiwisolver>=1.3.1……你只装了一个 matplotlib,结果多出十来个包,因为它们各自还要自己的依赖。
冲突的典型样子:A 要 numpy<2,B 要 numpy>=2,两个都要装,
pip 会挑一个然后把另一个的约束降级警告打出来。
看到警告别忽略,那通常是后面莫名其妙的运行错误的源头。
四、四类失败与对应查法
| 报什么 | 真实原因 | 怎么查 |
|---|---|---|
| Could not find a version | 没网或包名错 | pip -v;查 PyPI 的 wheel |
| Microsoft Visual C++ required | 没 wheel,需要现场编译 | 换 Python 版本,或找预编译的 wheel |
| ERROR: pip's dependency resolver | 版本冲突 | pip install -v 看约束链 |
| No module named xxx | 装到了另一个环境 | python -c "import sys; print(sys.executable)" |
最后一行那种错最常见,也最好查:
先确认你 pip 用的解释器和跑代码用的解释器是同一个。两个不一致,装多少次都没用。
统一写法可以避免九成麻烦:python -m pip install xxx,
少用裸的 pip——pip 这个名字可能指向另一个环境的脚本。
五、动手 Demo:装了没有、够不够版本、为什么装不上
用 importlib.metadata 读当前环境的包清单和版本, 再用 packaging 把「numpy>=2.0」这种要求解析成可判断的对象,逐条核对。 最后故意 import 一个没有的包,看真实报错长什么样。
import importlib.metadata as md
from packaging.requirements import Requirement
from packaging.version import Version
for spec in ("numpy>=2.0", "matplotlib>=3.5", "tensorflow>=2.0"):
r = Requirement(spec)
try:
cur = md.version(r.name)
ok = r.specifier.contains(Version(cur), prereleases=True)
print(spec, cur, ok)
except md.PackageNotFoundError:
print(spec, "没装")
print(md.requires("matplotlib")) # 它自己要的那些包
实跑输出:
--------------------------------------------------------------------
函式库的安装~Windows 篇~:装了没有、够不够版本
--------------------------------------------------------------------
这台机器上有 90 个已安装的包。按名字排序,前 8 个是:
包名 版本
----------------------------------
Markdown 3.10.3
PyPDF2 3.0.1
PySDL2 0.9.17
PyYAML 6.0.3
Pygments 2.21.0
anyio 4.15.1
av 18.1.0
bitarray 3.11.0
装库最常遇到的三个问题,一个一个查:
要求 当前版本 结论
----------------------------------------------
numpy>=2.0 2.5.2 满足
matplotlib>=3.5 3.11.1 满足
tensorflow>=2.0 没装 缺这个包
keras>=2.0 没装 缺这个包
**第一行第二行是「装了且够新」,第三行第四行是「压根没装」。**
深度学习框架就卡在这两类问题上:要么没装,要么装的版本和别的库打架。
真去装一个没有的包,报错长这样(这里是故意触发的):
ModuleNotFoundError: No module named 'tensorflow'
**看到这行别急着重装整个环境。**先问三件事:包名拼对了吗、
这个包里有没有子模块(numpy.core 之类)、当前解释器是不是你以为的那个。
第三件事最常见——开了两个环境,装的装到另一个去了。
最后看一眼依赖长什么样,以 matplotlib 为例,它自己列了这些要求:
contourpy>=1.0.1
cycler>=0.10
fonttools>=4.28.2
kiwisolver>=1.3.1
……共 9 条。**你装一个库,pip 会顺着这张单子把它要的也装上**,
所以「装一个」的结果常常是「多出五六个」——这就是依赖树。
90 个包,numpy 2.5.2、matplotlib 3.11.1 都满足要求;tensorflow 和 keras 直接是「没装」。
这台机器装不了深度学习框架,所以本书第 3 章之后,凡是书里用 Keras 写的,正文都标成「教材原码」,
实跑一律换成 numpy 手写。
ModuleNotFoundError: No module named 'tensorflow' 这一行是故意触发的。
注意它只说「没有这个名字的模块」,不说「包没装」——这两件事不一样:包可能装了,
但里面的子模块名不对,报错长得一模一样。
matplotlib 那张依赖单列了 9 条。pip 装它的时候,这 9 条会被顺着装下去。
所以「一个干净的 venv 装一个 matplotlib」结果会有十几个包——不是装错了,是依赖树本来就这么长。
这一段最实用的地方在于:判断「是不是环境问题」只要三步——打印 sys.executable、打印包版本、
import 一次看报错。三步之内能定位绝大多数问题。
30 秒实验
- 把
numpy>=2.0改成numpy>3.0,看结论那一列变成什么。 - 给
md.requires("matplotlib")加个循环,把带 extra 标记(分号后面那段)的挑出来,看有几条。 - 在 venv 里跑同一段脚本,看包数从 90 变成几个——这就是「干净环境」的样子。
常见误区
- 用管理员权限 pip 装到全局。 装得快,出问题只能重装 Python。永远在 venv 里装。
- 看到红字就重装整个 Python。 先看最后三行:缺编译器就去装编译器或换版本,缺包就换个包名, 环境错了就切环境。重装是最贵的做法。
- 混用 conda 和 pip。 同一个环境里混着装,依赖解析各算各的, 最后往往整成一个谁也升不动的死环境。
自测三问(点开对答案)
1. wheel 和源码包有什么区别? —— wheel 是预编译的二进制包,解压就能用;源码包要现场编译,需要编译器和对应的库。 Windows 上装不上,多数是因为没有 wheel 而要现场编译。 2. 为什么推荐 `python -m pip install` 而不是直接 `pip install`? —— 因为 `python -m pip` 一定用当前这个解释器自带的 pip, 而裸 `pip` 可能指向 PATH 里另一个环境的脚本,装到别处去。 3. 依赖冲突的典型症状是什么? —— pip 打出 resolver 的警告或报错,说某个包要求 A 版本而另一个要求 B 版本; 或者装完之后运行时报「某个属性不存在」——那是版本降级导致的 API 变化。Windows 的包装完了,Mac 上其实也一样,只是包管理器换成了 conda 或 brew。 下一节讲真正该学的一件事:怎么把环境写下来,换台机器一次装回去。
- ☐ (本节完,下一节 2.4 函式库的安装~Mac 篇~)