包管理器:别人造好的轮子,一行命令拿过来
什么是包管理器?
你想吃番茄炒蛋。你可以:
- 自己种番茄、养鸡、等鸡下蛋(从零造轮子)
- 去超市买番茄和鸡蛋(用包管理器安装别人写好的库)
包管理器就是程序员的"超市"。你告诉它你要什么,它帮你下载、安装、更新、卸载——一条龙服务。
| Python | JavaScript | |
|---|---|---|
| 包管理器 | pip | npm(或 yarn、pnpm) |
| 包仓库 | PyPI | npmjs.com |
| 包的数量 | ~50 万个 | ~200 万个 |
| 安装命令 | pip install | npm install |
npm 的包数量是 PyPI 的 4 倍——不是 JS 开发者更勤快,而是 JS 社区有个"微包"文化:连 is-odd(判断奇数)这种一行代码能搞定的事情都有人发了一个包。这是褒是贬,见仁见智。
基本命令对比
安装包
| 操作 | pip | npm |
|---|---|---|
| 安装 | pip install X | npm install X |
| 指定版本 | pip install X==1.0 | npm install X@1.0 |
| 升级 | pip install --upgrade X | npm update X |
| 卸载 | pip uninstall X | npm uninstall X |
| 安装全部依赖 | pip install -r requirements.txt | npm install |
| 查看已安装 | pip list | npm list |
依赖清单:requirements.txt vs package.json
当你把项目分享给同事,他怎么知道要安装哪些包?答案是:依赖清单。
| requirements.txt | package.json | |
|---|---|---|
| 格式 | 纯文本 | JSON |
| 生成方式 | 手动 / pip freeze | npm init + 自动维护 |
| 区分开发依赖 | 不区分(需要两个文件) | dependencies vs devDependencies |
| 包含其他信息 | 只有依赖 | 项目名、版本、脚本、入口等 |
| 锁文件 | 没有(可选 pip-tools) | package-lock.json(自动生成) |
package.json比requirements.txt功能强大得多——它不只是依赖清单,更是项目的"身份证"。Python 社区现在也有了更现代的方案pyproject.toml,但requirements.txt仍然是最常见的。
pip freeze 会把当前环境里所有的包都输出,包括你不直接使用的间接依赖。这会导致 requirements.txt 里有一大堆你不认识的包。
npm 不会有这个问题——package.json 只记录你直接安装的包,间接依赖由 package-lock.json 管理。
Python 社区的解决方案是用 pip-tools(pip-compile)或者 poetry 来更好地管理依赖。
虚拟环境 vs node_modules
Python 的烦恼:全局污染
Python 的 pip 默认把包装到全局。如果项目 A 需要 requests 2.28,项目 B 需要 requests 2.31——冲突了!
解决方案:虚拟环境(virtual environment)。
JS 的方案:每个项目自带一个"超市"
npm 默认把包装到项目目录下的 node_modules/ 文件夹里。每个项目的依赖互不干扰。
| Python venv | Node.js node_modules | |
|---|---|---|
| 目的 | 隔离不同项目的依赖 | 天然隔离(每个项目独立) |
| 需要手动创建? | 是,python -m venv .venv | 不用,npm install 自动创建 |
| 需要激活? | 是,每次打开终端都要 | 不需要 |
| 体积 | 较小 | 巨大(传说中的"宇宙最重物质") |
| 提交到 git? | 绝对不要 | 绝对不要 |
node_modules有个梗:它是宇宙中最重的东西,比黑洞还重。一个中型项目的node_modules可以轻松超过 500MB。但别担心,这些都不需要提交到 git——别人拿到你的package.json后执行npm install就能重新生成。
npm 脚本:package.json 的隐藏技能
package.json 还有一个杀手锏——scripts,让你自定义命令:
实际工作流对比
当你接手一个新项目时:
全局安装 vs 本地安装是新手常踩的坑:
npm install -g xxx:全局安装,所有项目都能用——通常只用于 CLI 工具(如typescript、nodemon)npm install xxx:本地安装,只有当前项目能用——绝大多数包都应该本地安装
Python 的 pip 默认就是全局安装(所以需要虚拟环境来隔离),npm 默认是本地安装(天然隔离)。
经验法则:如果你在写代码里 import 它,就本地安装。如果你在终端里当命令用,才考虑全局安装。
试试动手做一个小项目的初始化练习:
Python 版:
- 创建一个文件夹
my-python-app - 创建虚拟环境并激活
pip install requests- 用
pip freeze > requirements.txt生成依赖清单 - 写一个
main.py,导入 requests 并请求https://httpbin.org/get
Node.js 版:
- 创建一个文件夹
my-node-app npm init -y初始化项目npm install axios- 写一个
index.js,导入 axios 并请求https://httpbin.org/get
对比一下两个流程,感受一下"虚拟环境"和"node_modules"的不同体验。
小结
| 概念 | Python | JavaScript |
|---|---|---|
| 包管理器 | pip | npm(或 yarn、pnpm) |
| 依赖清单 | requirements.txt | package.json |
| 锁文件 | 无(可选 pip-tools) | package-lock.json |
| 隔离方案 | 虚拟环境(venv) | node_modules(自动隔离) |
| 脚本系统 | Makefile / 无 | npm run xxx |
| 安装全部依赖 | pip install -r requirements.txt | npm install |
一句话:pip 和 npm 都是你的"超市",但 npm 这家超市自带停车场(node_modules),而 pip 需要你自己找停车位(venv)。 不管用哪个,记住一个原则:别重复造轮子,善用别人的劳动成果——这就是拿来主义的精髓。