前言
pip是 Python 生态里的包安装工具,由 Python 打包权威组织(PyPA)维护。要弄清它的身份:它不是标准库里的模块,你写import pip虽然大多数情况下能成功,但官方并不推荐在代码里这么用;它是由 CPython 官方安装包通过ensurepip机制默认引导安装的一个独立程序。
使用pip最大的坑不在命令本身,而在装到哪里去了。很多人在系统 Python 上直接pip install,把几十个包灌进全局环境,结果不同项目要不同版本的同一个库时互相打架,甚至把系统的 Python 环境弄坏。正确姿势只有一条:先建虚拟环境,再在虚拟环境里装包。
本文按「用什么命令调用、装包卸载、依赖清单、可编辑安装、换源、以及如何避免污染系统环境」的顺序,把pip的常用操作讲清,并给出一份真会踩的坑点清单。
一、用哪种方式调用 pip
调用pip有两种写法:直接敲pip,或者写成python -m pip。推荐后者,原因很实在——pip这个可执行文件在 PATH 里可能指向另一个 Python 环境,而python -m pip明确表示「用当前这个python对应的 pip」,不会指错人。
# 查看当前 python 对应的 pip 版本与位置
python -m pip --version
# 确认是哪个环境
python -c "import sys; print(sys.executable)"第二条命令会打印出当前解释器的可执行文件路径。如果它指向系统目录而不是你的项目里的.venv,那你现在装包就会装进系统环境——这是判断「我在哪个环境里」的最快方法。
要升级 pip 本身,官方推荐的写法是:
# 升级 pip 自身
python -m pip install --upgrade pip这里用python -m pip而不是pip,正是为了确保升级的是当前环境里的那个 pip。
二、安装与卸载
# 安装一个包
python -m pip install requests
# 指定版本
python -m pip install "requests==2.31.0"
# 指定最低版本
python -m pip install "requests>=2.31"
# 从本地 wheel 文件安装
python -m pip install ./dist/demo_app-0.1.0-py3-none-any.whl
# 卸载
python -m pip uninstall requests版本约束要用引号包起来。在大多数 shell 里,>和<是重定向符号,不引号会被 shell 吃掉,导致python -m pip install requests>=2.31被解析成「把输出写到 2.31 文件」,命令行为完全错乱。
查看已安装的包和某个包的详情:
# 列出已安装的包
python -m pip list
# 只看过时的包
python -m pip list --outdated
# 查看某个包的详细信息(版本、位置、依赖、主页等)
python -m pip show requestspip show输出的Location一栏会告诉你这个包装在哪个目录,是排查「为什么 import 不到」时最有用的信息之一。
三、依赖清单与 requirements.txt
pip freeze把当前环境里已安装的包按「包名==版本」的格式输出,正好可以直接当依赖清单用。
# 导出当前环境的完整依赖清单
python -m pip freeze > requirements.txt
# 按清单还原环境
python -m pip install -r requirements.txt生成的文件内容是「包名==版本」一行一条,格式大致如下(版本号仅示意,实际以你环境里的为准):
certifi==2024.2.2
charset-normalizer==3.3.2
idna==3.6
requests==2.31.0
urllib3==2.2.1要清楚pip freeze的一个局限:它导出的是当前环境里所有包,包括你的项目并没有直接使用、只是被别的包连带装进来的传递依赖。所以requirements.txt里常常混着一堆你没听说过的包。这在「精确复现环境」时是优点,在「表达项目真实依赖」时是缺点。想要更清晰的表达,可以用pyproject.toml的dependencies字段声明直接依赖,把requirements.txt留给部署锁定。
四、可编辑安装:pip install -e .
开发一个库时,你希望改了源码立刻生效,不想每次改完都重新安装。这时用「可编辑安装」(editable install):
# 在项目根目录执行,把当前项目以可编辑方式装进当前环境
python -m pip install -e .结尾的那个.表示「当前目录这个项目」。可编辑安装会在环境里建立一个指向源码目录的链接,而不是把文件复制过去,所以源码的修改能被立即看到。它需要项目里有可用的构建配置,通常是pyproject.toml。
# 只装开发用的额外依赖(如果项目里定义了 extras)
python -m pip install -e ".[dev]"方括号里的名字叫「extra」,需要在项目的构建配置里事先定义好,不是随便写的。
五、换源与索引
某些网络环境下,从默认包索引拉包很慢或超时,需要指定镜像源。pip提供了指定索引地址的参数:
# 临时指定索引地址(示例地址仅为占位,实际用哪个源请按需选择)
python -m pip install requests --index-url 你的索引地址
# 或者写进配置文件,长期生效
python -m pip config set global.index-url 你的索引地址--index-url指定的是「找包的主索引地址」,还有一个相关参数可以指定额外的、补充的索引,两者语义不同。具体用哪个镜像、地址是否仍然有效,请以你选定的镜像服务方的说明为准,因为镜像地址会变,本文不写死任何具体域名。
换源时有一条安全提醒:包索引是执行代码的来源,从一个不可信的索引装包,等同于在该机器上运行来历不明的代码。生产环境应使用经过校验的可信源。
六、虚拟环境:唯一正确的隔离方式
前面反复提到「别装进系统环境」。具体做法是每个项目配一个虚拟环境。
# 在项目目录里创建虚拟环境(目录名惯例叫 .venv)
python -m venv .venv
# 激活:Linux / macOS
source .venv/bin/activate
# 激活:Windows 的 PowerShell
.venv\Scripts\Activate.ps1
# 激活:Windows 的 cmd
.venv\Scripts\activate.bat激活之后,命令提示符前通常会出现环境名,此时python -m pip install 包名装的就是这个环境。用python -m pip --version或python -c "import sys; print(sys.executable)"确认路径指向.venv下的解释器,是最稳妥的验证方式。
如果不想激活,也可以直接调用环境里的解释器:
# 不激活,直接用虚拟环境里的 python(Windows 示例路径)
.venv\Scripts\python.exe -m pip install requests虚拟环境目录(通常.venv)不应提交到版本控制,把它写进忽略规则即可;别人拿到项目后自己建环境、按requirements.txt还原。
七、实战:从零搭一个隔离环境
# 1. 建目录进目录
mkdir demo-pip && cd demo-pip
# 2. 创建虚拟环境
python -m venv .venv
# 3. 激活(按平台选一条)
source .venv/bin/activate
# 4. 确认 pip 属于这个环境
python -m pip --version
# 5. 升级 pip 并安装依赖
python -m pip install --upgrade pip
python -m pip install requests
# 6. 锁定依赖
python -m pip freeze > requirements.txt
# 7. 写代码并运行
python app.py配套的app.py:
# 适用于 Python 3.8+
import sys
def main():
print("解释器:", sys.executable)
try:
import requests
except ImportError:
print("未安装 requests,请先在这个环境里执行安装命令")
return
print("requests 版本:", requests.__version__)
if __name__ == "__main__":
main()逐行推演:sys.executable打印当前解释器路径,用来确认「我到底在哪个环境里」——如果它指向系统目录而不是.venv,说明第 3 步的激活没成功。import requests放在try里,未安装时给出可操作的提示而不是抛栈。这里只用了requests.__version__这一个属性名,不涉及任何具体 API 细节,避免记错签名。
常见坑点
坑点 1:直接往系统 Python 里装包。❌pip install requests装在系统环境,多个项目共用一个环境,版本互相冲突,严重时弄坏系统工具链。 ✅ 每个项目用python -m venv .venv建隔离环境后,再在里面安装。
坑点 2:环境搞混,装错了地方。❌ 激活了虚拟环境却敲pip install x,而 PATH 里的pip指向系统环境;或者报了ModuleNotFoundError就反复改代码,其实包根本没装进当前环境。 ✅ 统一用python -m pip install x;排查时先跑python -c "import sys; print(sys.executable)"和python -m pip show 包名确认解释器与安装位置。
坑点 3:版本约束没加引号。❌pip install "requests>=2.31"写成pip install requests>=2.31——shell 把>当重定向,命令行为错乱。 ✅ 加引号:python -m pip install "requests>=2.31"。
坑点 4:把.venv提交进版本库。❌git add .把整个.venv目录提交——体积巨大、路径写死、换机器就没用。 ✅ 把.venv/写进忽略规则,只提交依赖清单或项目声明文件。
坑点 5:以为pip freeze只导出直接依赖。❌ 拿pip freeze的输出当「项目依赖列表」做代码审计——它包含全部传递依赖。 ✅ 想表达直接依赖用pyproject.toml的dependencies;pip freeze留给环境复现。
坑点 6:忘了升级 pip 就装需要新版本 pip 的包。❌ 用很旧的 pip 安装一个用了新元数据格式的包,报构建或解析错误。 ✅ 先python -m pip install --upgrade pip再安装。
坑点 7:从不信任的索引装包。❌ 为了图快,把--index-url指向一个来路不明的镜像——安装过程会执行该源提供的代码。 ✅ 使用可信索引;对来源存疑的包,先审查再安装。
坑点 8:在错误的目录执行pip install -e .。❌ 在项目根目录之外执行,安装的是别的项目(或直接报找不到构建配置)。 ✅cd到含pyproject.toml的项目根目录,再执行python -m pip install -e .。
总结
| 目的 | 命令 |
|---|
| 确认环境 | python -c "import sys; print(sys.executable)" |
| 升级 pip | python -m pip install --upgrade pip |
| 安装 | python -m pip install 包名 |
| 指定版本 | python -m pip install "包名==1.2.3" |
| 卸载 | python -m pip uninstall 包名 |
| 导出依赖 | python -m pip freeze > requirements.txt |
| 还原依赖 | python -m pip install -r requirements.txt |
| 可编辑安装 | python -m pip install -e . |
| 建虚拟环境 | python -m venv .venv |
pip的命令一共就那么几个,真正决定成败的是环境管理:先隔离,再安装,用python -m pip而不是pip,用sys.executable确认自己在哪。把这三条变成肌肉记忆,绝大多数「昨天还能跑今天就不行了」的问题都会消失。