究竟什么是 API:
"API" 这个词今天几乎无处不在——AI、Agent、大模型、天气、地图……张口就来,听起来很神秘;这里不解释、不打比方,直接拿两个真的 API 来,亲手调用一下,就明白了
从生活中说起:
不止一个人问过:究竟什么是 API?比如有位朋友,他听说 Claude 特别厉害想用一下,找了个渠道说提供 API,就跑来问这个 API 是什么意思
从这里开始进入后端部分,就从 API 讲起;理解它特别重要:无论想做 web 开发、手机 app 开发,还是想认真理解 AI 时代这些新东西,几乎都绕不开——有的 API 能查天气,有的能拿到大模型的回复,有的能帮我们做计算,它无处不在;而且正好走到这儿了:还记得吗,文字实验室那一页点 "开始分析" 是没反应的,拼音和情感分数都是写死的假数据;要让它真的能算,就得给网站补上一个 "后端",而前端和后端之间怎么对话,靠的也是 API
有人讲 API 时爱打比方,比如把它比作餐厅的后厨——这种比喻有时适得其反,反而让人更迷糊;理解 API 最快的方式,就是亲自找一个调用一下;调完你自己就知道它是什么了;如果还能自己做一个,那就完全通透;学任何概念类的东西都是这样:没用过,很难解释;用过一两次,就不需要解释
那就先找一个 API 用一下
第一个:查一下你自己的公网 IP
先调用一个零门槛的——不用注册、不用花钱、不用申请任何东西
有一个网站 ipify.org,它是一个免费开放的服务,只干一件事:告诉你此刻的公网 IP 是多少(公网 IP 就是你在互联网上的 "地址",前面讲过)。主页上显示的那个 IP,就是你现在的 IP 地址
除了网页,它还提供 API 服务;先介绍一个新的终端命令:curl——一个在终端里发网络请求的小工具;平时用浏览器访问网址,其实用终端也可以访问:curl 就是在命令行里访问一个网址时用的,它会把服务器原样返回的内容直接打印出来,特别适合试 API(macOS 和大多数 Linux 都自带)
打开终端,把下面这行粘进去,回车:
curl "https://api.ipify.org?format=json"网址用引号括起来——也可以不用,但因为网址里有?这样的符号,终端可能会误解,加上引号最稳妥,意思是告诉终端 "这一整串都是网址"
回车之后,很快终端里回来一小段 JSON:
{ "ip": "114.86.123.45" }就这么一句:没打开任何网站,就问到了自己此刻的公网 IP——就是 ip 那个字段(你看到的会是你自己的 IP);整个响应就一个字段,干干净净
这个请求简单到可以直接把那串网址粘进浏览器地址栏回车,看到同样的一段数据——这也顺带说明一件事:平时用浏览器打开网址,本质上也是在向服务器 "发请求、拿响应"
刚才做的这件事,就叫 "调用 ipify 的 API"
第二个:调用 DeepSeek 的 API
再调用一个不一样的。这次不是 "查一份数据",而是调用 DeepSeek 的大模型,让它回一句话
这个稍微有点门槛,因为对方得知道 "是谁在调"(一来算用量,二来防止被乱用),所以要先拿一把 "身份钥匙" ——API Key:
注册 / 登录 DeepSeek 开放平台:platform.deepseek.com
找到 API keys 页面,点击创建 API keys,起一个名字,就能创建一个 API key——得到一串以
sk-开头的字符串,复制存好(只完整显示这一次)DeepSeek 的 API 按用量计费,需要充一点点余额——别担心,就调用几次,一次花不了几分钱
完整、最新的说明以官方文档为准:api-docs.deepseek.com/zh-cn/;照着别人的文档,用上别人的能力——这本身就是这里想让你体会的事;如果此刻实在不想充值,可以先跟着往下读、把道理看懂;但强烈建议亲手调用一次,那种 "我居然直接用上了大模型" 的感觉,非常值得
拿到 key 后看 "接口文档",里面提供了用 curl 调用对话 API 的示例:
curl https://api.deepseek.com/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${DEEPSEEK_API_KEY}" \ -d '{ "model": "deepseek-v4-pro", "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"} ], "thinking": {"type": "enabled"}, "reasoning_effort": "high", "stream": false }'把示例里的${DEEPSEEK_API_KEY}换成刚复制的那段sk-开头的 key;其他部分建议把 Hello! 改成别的 prompt,比如 "你好,请用一句话介绍你自己":
{"role": "user", "content": "你好,请用一句话介绍你自己"}把改完的示例粘贴到终端,回车;稍等一下,回来的数据里(删掉次要字段后)大概是:
{ "choices": [ { "message": { "role": "assistant", "content": "你好!我是 DeepSeek,一个由深度求索打造的 AI 助手,很高兴为你服务。" } } ] }看到这样的回应就成功了:没打开任何网页,就在自己的终端里,让 DeepSeek 的大模型回了一句话,答案藏在 choices → message → content 里——这就是 "调用 DeepSeek 的 API"
API 是设计给计算机程序用的:
不用 API 也行:查 IP 可以直接访问 ipify.org,用 DeepSeek 可以开它的网页或手机 app;但如果是一个计算机程序想查 IP、想用 DeepSeek 的大模型,网页的方式就行不通了——程序总不能每次都去打开一个浏览器
所以对程序调用来说,最友好的方式就是 API——它的设计本身就是为计算机程序服务的
这种 "把自己的能力,持续地通过一个固定的入口对外提供出去,让别的程序来调用" 的做法,是整个软件世界的通行做法;这个对外的入口就是 API,英文全称 Application Programming Interface(应用程序编程接口)
API 的格式标准:
把刚才两次调用放在一起看:两个 API 功能不同,但调用方式几乎一模一样——
向一个 URL 地址发起请求(api.ipify.org、api.deepseek.com)
发请求时按对方的要求带上该带的信息(没有要求可以不带)
对方在它自己那边处理(我们看不见、也不用管)
它回给我们一段数据(一般是 JSON)
这就是 API 的形态:只要按它规定的方式来请求,就能用上它的能力,完全不需要知道内部怎么实现——这就是 API 的意义:让能力可以被别人 "对接" 过去用
不过上面两个案例用了两种请求方式:查 IP 那次是取数据(叫 GET),DeepSeek 那次需要提交内容(叫 POST);GET 和 POST 是 API 最常用的两种请求方式,但标准不止这两种,还有 PUT、DELETE 等,遇到时再介绍
当 API 有了格式标准,我们就不必在意对方用什么语言实现:只要按规范请求、按规范响应,调用方和提供方都可以用任意语言或框架;所以我们用 DeepSeek 的 API,不需要关心它是用 Python 还是 C 写的;DeepSeek 也不关心我们的请求是 curl 发的还是 Python 发的
为什么 AI 时代,到处都是 API:
理解了这一点,就能解除 AI Agent 的 "神秘感":
平时用的各种 AI 产品,很多本质上就是在调大模型的 API——把我们的话包装一下发过去,把答案拿回来,再包装成好看的界面
那些看起来无所不能的 AI Agent,本事来自一件件 "工具":凡是要联网用别的服务的——查天气、查快递、搜网页、往群里发消息、再喊另一个大模型帮忙……基本都是在调 API;另一些则是直接在你电脑上跑命令、读写文件(严格说不算网络 API,但骨子里是一回事:照着一个固定的接口,去调用别人已经做好的能力)
换句话说:AI 工具之所以看起来无所不能,就是因为它在不停地调用各种现成的能力——其中很大一部分就是 API;理解了 API,就揭开了这些工具神秘面纱的一大半
回到我们的网站:前端调后端,也是调 API
我们自己的项目马上要用到一模一样的逻辑
到目前为止网站只有前端——用户在浏览器里看到、点到的那些页面,前端很擅长展示和交互;但文字实验室那个 "根据你输入的文字,算出情感分数和拼音",前端干不了,需要一个专门负责计算和处理的程序——这就是后端
那前端怎么把 "用户输入的文字" 交给后端、又怎么把 "算出的分数" 拿回来?答案就是:给自己的网站也做一个 API——就像 DeepSeek 那个 /chat/completions 一样,只不过这个 API 是我们自己写的、专门算拼音和情感分数的;到时候前端向我们自己的 API 发一个请求(带上用户输入的文字),后端算完回一段 JSON,里面既可以包含拼音,也可以包含情感分数
你看,和你刚才调 DeepSeek 是同一回事。接下来几节要做的,就是给网站补上一个后端,并写出我们自己的 API
那 "后端" 到底是个什么东西:
既然反复提到后端,有必要把这个词解释一下:
前端:跑在用户的浏览器里,负责看得见的展示和交互
后端:一个一直运行、守在服务器上、等着接收请求的程序,负责看不见的计算、处理,以及把数据存下来
刚才 ipify 和 DeepSeek 那两台 "一直守着、等你发请求" 的程序,就是它们的后端:我们的请求发过去,它们接住、处理、回话;接下来要为自己的网站做的,就是这样一个(相比之下小得多的)后端;而 API,就是前端用来调用后端的那个入口
后端可以用很多种语言写:
"做一个能对外提供 API 的后端",用什么编程语言都能做:JavaScript (Node)、Python、Go、Java、PHP、Ruby、C#……都可以;ipify、DeepSeek 的后端各自用什么语言写的,我们不知道,也不影响调用它们的 API——因为 API 这个入口,和它内部用什么语言实现,是两回事
这里选 Python 来写后端,原因有两个:一是它的生态比较成熟,尤其在算法、数据、AI 这些方向——文字实验室要算的 "拼音”和“情感分数”正好能借上这个力;二是它的语法对初学者比较友好
但有一件事值得记住:Python 只是开发 API 的其中一个选择,API 这个概念和用什么语言无关
装好 Python:环境、venv 与第一个程序
把 Python 装到电脑上,给项目建好自己的专属环境 (venv),跑起第一个 Python 程序、认一认代码结构,再动手装一个第三方库 (requests) 用 Python 调一次 API——pip、requirements.txt 一并落地;后端要用的环境,一次备齐
我们需要 Python 了:
已经亲手调用过两个 API,目标也定了:接下来用 Python 给网站写一个自己的 API;要运行 Python 写的代码,电脑上得先有 Python
这个感觉应该不陌生:做过前端实战的话,很容易想到本地运行 JS 代码之前要先装 Node——Vite、Next 那一套都得靠 Node 才能跑起来;后端同一个道理:
先有运行环境,再谈写代码前端项目的运行环境是 Node;后端用 Python 写,运行环境就是 Python;这一部分把后端要用的环境一次备齐
装 Python:
安装前可以先确认电脑上是否已经有 Python:
python3 --version # 打印出 Python 3.x 的版本号,就装好了或者(Windows 一般输入 python 而非 python3):
python --version打印出 Python 3.x 的版本号,说明已经安装了
如果打印出 Python 2.x,要注意:2.x 官方已不再维护,不建议再用
无论是否已装过,都建议重新安装一下最新版(多个不同版本的 Python 可以共存,不用担心冲突);安装方式和当初装 Node 一样:打开 Python 官网下载页 python.org/downloads/,下载最新稳定版安装包(macOS 是 .pkg,Windows 是 .exe),双击一路默认下一步;装完后重新开一个终端窗口,再跑一次版本命令验证
python3 和 python:
为什么 macOS 上敲的命令是 python3 而不是 python?
和 JavaScript 一样,Python 诞生也已有几十年,经历过一次不兼容的大版本升级:早期几乎所有开发者都在用 Python 2;后来官方为修复历史设计问题推出了 Python 3,但这次升级并不平滑——Python 3 有不少语法和行为与 Python 2 不兼容;这意味着很长一段时间里,一台电脑可能需要同时装 Python 2 和 Python 3(老项目只能跑在 2 上,新项目推荐 3)
为了避免混淆,许多 Linux 和 macOS 系统约定:python 指向 Python 2(或保留为空),python3 明确指向 Python 3——久而久之 python3 成了许多系统和教程里的标准写法;不过随着 Python 2 正式停止支持(2020 年),如今越来越多的系统重新把 python 指向了 Python 3,例如 Windows 官方安装器和很多现代 Linux 发行版里,直接输入 python 启动的就是 Python 3
对我们来说:分别试一下,哪个能用就用哪个
如果电脑里不止一个 Python
从没装过 Python 但电脑上却有——这很正常:可能是操作系统自带的,也可能是以前装别的软件时顺带装上的;前面说过,一台电脑上可能同时住着好几个 Python
那问题来了:敲 python3 的时候,用的到底是哪一个?有一个终端命令可以回答;macOS 下输入:
which python3各系统对照:
| 操作系统 | 命令 |
|---|---|
| macOS | which python3 |
| Linux | which python3 或 command -v python3 |
| Windows(CMD) | where python |
| Windows(PowerShell) | Get-Command python 或 where.exe python |
它会打印出一条路径——这就是此刻敲 python3 时真正被执行的那一个;还可以更进一步,把候选名单全列出来:
which -a python3你可能会看到好几条路径(每台机器不一样,多少不等)——排在最前面的那个,就是当前生效的
一个值得记住的生存技能:以后遇到 "版本不对" "明明装了却找不到" 这类怪事,第一招就是 which python3(macOS / Linux)或 where python(Windows)——先搞清楚自己此刻用的是哪一个 Python,很多环境问题看一眼路径就真相大白
如果某次明确想用某一个版本,但它不是 python3 指向的默认版本,可以直接在命令里指明版本号;比如电脑上同时有 python3.12 和 python3.14,默认 python3 指向 3.14:
% python3 --version Python 3.14.6想用 3.12,就不用 python3,直接用 python3.12:
% python3.12 --version Python 3.12.9venv 与环境隔离:
盘点一下现状:电脑里可能住着好几个 Python,python 和 python3 还可能各指各的——每次都要靠 which 确认 "现在用的是哪一个",这本身就是负担;这是版本管理的困境
此外还有另一个问题:我们需要安装第三方库、工具包,而这些包也各有版本;以后电脑上不会只有一个 Python 项目,它们各自需要的工具包、甚至包的版本都可能不一样——如果全挤在同一份公共 Python 里,早晚会打架
什么叫第三方库?还记得前端的 anime.js 动画库吗?那就是 JS 生态里的一个第三方库;Python 生态这样的库也非常多,几乎肯定会用到
所以事情复杂了:首先电脑上有不同版本的 Python,不同项目可能依赖不同版本;其次每个项目还各自依赖不同版本的工具包;前端依赖讲过一条规矩——依赖应该跟着项目走,每个项目有自己的 node_modules;Python 项目应对同样的处境,也有相似的方案
Python 官方的解法是:别在系统那堆 Python 里纠结,给每个项目配一套自己专用的环境——术语叫虚拟环境(virtual environment);Python 自带了一个做这件事的工具,叫 venv
一个示例:
假设一个项目在 ~/project_A,需要 Python 3.12;进入项目目录,创建一个 .venv:
cd ~/project_A python3.12 -m venv .venv这个 .venv 是一个目录,它帮我们管理当前目录的 Python 环境——用哪个版本的 Python、装了哪些第三方包、各是什么版本
但创建之后还不能立即使用(这点和 Node 的 package.json 不同):.venv 还需要激活
source .venv/bin/activate激活之后,终端命令行最前面会自动带上(.venv)标识。此时无论用 python 命令(此刻可以用 python 了,哪怕之前只能用 python3)还是 python3,都只会指向 Python 3.12;安装第三方库时也只会装到 ~/project_A 这个项目的 .venv 之中,而不是全局
如果关闭终端再开一个新的,(.venv) 就消失了,虚拟环境也就退出了;也可以不关终端,显式退出:
deactivate常见疑问:
两个项目的虚拟环境目录都叫 .venv,激活后都显示 (.venv),怎么区分?
目录不是必须叫 .venv,但这是约定俗成的名称,许多配套工具(例如 VS Code)都认得它,尤其是 AI 认得它,不建议变更;想让提示符不同,可以在创建时给它一个自定义提示符:
python3 -m venv --prompt=project_A .venv这样 venv 目录名仍是 .venv,但终端上看到的不再是 (.venv) 而是 (project_A)
已经在用 miniconda / anaconda 了,接下来怎么用 venv?
如果每次打开终端,命令行最前面都有一个(base)提示符,那大概率说明你已经在用 miniconda / anaconda(统称 conda);conda 也能管理 Python 虚拟环境;如果你已经在用 conda,就不再建议换用 venv 混着管——两者是完全不同的环境管理策略
conda 实际上是全局安装的,用它自己的方式管理多个环境,每个环境有自己的名字,默认叫 base,用户可以自建(比如 myenv312),每个环境可以装不同的 Python 版本;conda 的 "侵略性" 比较强:一旦按官方指引装好,每次启动终端它都会跟着启动,此时直接输入 python,跑的就是 conda 的默认环境 (base)
和 venv 不同,conda 不会在项目里创建类似 .venv 的目录,项目自身不保存它所依赖环境的上下文,需要开发者自己记住 "哪个项目对应哪个环境";从这个角度说,在 vibe coding 时代 venv 反而更有优势——AI Agent 可以在项目里明确理解项目的依赖;后续都用 venv 管理环境;如果你在用 conda 且想改用 venv,建议先退出 conda
如何退出 conda:
如果每次打开终端都看到 (base),可以执行下面的命令关闭 conda 的自动启动:
conda config --set auto_activate_base false有个版本差异要注意:较新版本的 conda(24.9 及以后)把这个配置项改名成了 auto_activate,所以新版也可以写成:
conda config --set auto_activate false新版用 auto_activate_base 仍然有效,只是会多打印一句 "该项已弃用" 的警告;两条命令哪条不报错就用哪条——旧版认前者,新版两者都认。执行之后关闭终端再打开,就不会看到 (base) 了,以后启动终端也不会默认进入 conda 环境
这条命令只是不再默认启动 conda,并不代表 conda 被移除:以后需要时用 conda activate 重新进入,用 conda deactivate 退出
在项目中创建后端目录和 .venv:
环境问题搞定,回到自己的项目:创建一个后端目录,用 Python 小试牛刀;给后端代码安个家,就放在贯穿全程的项目里:
cd ~/zero-to-tech mkdir backend cd backend这里可能冒出一个问题:后端有了 backend/ 目录,要不要也建一个 frontend/、把前端挪进去,弄得对称一点?
这里选择不挪;新起的全栈仓库确实常见 frontend/ 和 backend/ 并列,但我们这个仓库不是设计出来的,是长出来的:它从一个静态页开始,一路长成 React、再长成 Next,前端占着根目录,是它成长的年轮——这也是真实老项目的常态:结构带着历史痕迹,只要不碍事,就不为了对称而重构;现在它一点都不碍事:前端在根目录照常 npm run dev,后端在 backend/ 里各干各的,互不打扰,而且之前配好的 Nginx 也全部继续有效;哪天真碍事了(比如要把前后端拆成两个仓库),再挪不迟——到那时你已经有能力自己挪了
顺便这也回答了 "前后端的独立体现在哪":不在目录的组织方式上,而在两个独立的进程、两套独立的依赖、两种独立的部署方式上——接下来会挨个碰到
然后在 backend/ 里创建虚拟环境(顺手用上刚学的 --prompt,起个一眼能认出的名字):
python3 -m venv --prompt=zero-to-tech .venv执行完,ls -a看一眼——多了一个 .venv 文件夹。它就是虚拟环境本身:里面放着一份专属于这个项目的 Python(还有一个叫 pip 的工具——干什么的,等真正需要的那一刻再说)
建好了,先激活:
source .venv/bin/activate注意看提示符,前面多了一个(zero-to-tech):
(zero-to-tech) libo@Mac backend %这个括号在提醒你:你现在用的,是这个项目自己的那套 Python;空口无凭,拿刚学的 which 验证一下:
which python # → /Users/你的用户名/zero-to-tech/backend/.venv/bin/python which python3 # → /Users/你的用户名/zero-to-tech/backend/.venv/bin/python3两条路径都指进了 .venv——刚才那一堆候选 Python 带来的混乱,在这个项目里就此终结:python 和 python3 指向同一份,就是项目自己的这份,再无悬念
想退出来的时候,一个词:
deactivate提示符前的(zero-to-tech)消失,你又回到了系统环境;感受完就再 source .venv/bin/activate 回来;从今往后给自己立个习惯:进这个项目干活,先激活
Windows 的同学:激活命令是 .venv\Scripts\activate,其余一致
一个小工具:VS Code 有微软官方的 Python 扩展(左侧 "扩展" 面板搜 Python,装微软出的那个——它同时负责 Python 的语法高亮、补全、调试,第一次写 Python 建议装上);装好后它会自动认出项目里的 .venv;以后在 VS Code 里新开终端,它会自动帮我们激活环境
顺手立一条规矩:.venv 不进 Git;它和 node_modules 一个性质——本地生成、体积不小、随时可重建;在项目的 .gitignore 里加上一行:
backend/.venv/第一个 Python 程序:
环境好了,写一个程序运行一下:用 Python 生成一段 JSON;为什么是 JSON?回想上一部分——API 回给调用方的基本都是 JSON,这正是我们的后端马上要天天干的事
确认自己还在 backend/ 目录、提示符带着 (zero-to-tech),用 VS Code 打开这个目录,新建一个文件 first_json.py,写入:
import json site_name = "zero-to-tech" def make_data(): data = {"message": "hello, world", "from": site_name} return json.dumps(data) print(make_data())回到终端,运行它(运行前先确定当前目录下有这个文件):
python3 first_json.py终端打印出:
{"message": "hello, world", "from": "zero-to-tech"}一段 JSON 出来了——说明 Python 运行环境已经好了;可以看到,运行一个 Python 程序就是 "一条 python3 命令 + 一个 .py 文件",就这么直接:不用构建、不用编译、不用浏览器;以前 JS 代码靠浏览器跑,现在 Python 代码靠 python3 跑
顺着这几行代码,认一认 Python:
先说清楚:这不是语法课——有 AI 的时代,语法可以边用边查;我们真正需要的是认得结构:看到一段 Python 代码,知道它大致的写法(看不懂也没关系);刚才这个程序虽然短短几行,但已经是比较典型的 Python 代码文件,从上往下看
引入库:
import json第一行通过 import 引入一个 json 库;Python 安装时就自带一大批现成的工具,统称标准库——要用哪个,import 一下就能用,不用另外安装;这个 json 是标准库的一员,作用是处理 JSON 这种格式;常见的标准库成员还有:
datetime——日期和时间
random——随机数
os——和操作系统打交道(文件、路径、环境变量)
http.server——一个能接收网络请求的小服务器(注意这个,马上会用到)
有标准库自然就有第三方库——不是 Python 自带、而是世界各地的开发者写好后发布到网上的库;用第三方库要先安装才能 import;这套逻辑前端见过:anime.js 就是用 npm install 装回来的第三方库;Python 的第三方库装到哪儿?你今天已经准备好答案了——装进 .venv 这个项目专属的环境里;怎么装,下一段就装一个、用一个
变量:
site_name = "zero-to-tech"第二行定义了一个叫 site_name 的变量,值是 "zero-to-tech"——写法很容易理解,就是直接的 名字 = 值
函数,以及缩进:
def make_data(): data = {"message": "hello, world", "from": site_name} return json.dumps(data)def 用来定义函数;注意函数体是靠缩进表示的——这是 Python 最显眼的规矩:JS 用花括号{}圈定代码块,Python 里缩进本身就是语法,哪些行缩进对齐,哪些行就属于同一块;函数里最后一行是 return,表示这个函数最终给出的结果
打印:
print(make_data())print 的意思是在终端上打印(显示)内容——这一行就是把 make_data() 的结果打印到终端,也就是把函数里定义的 data 以 JSON 格式打出来
装第一个第三方库:用 Python 调一次 API
first_json.py 里的 json 是标准库,import 就能用;但让 Python 真正强大的,是海量的第三方库。光说不练假把式——这就装一个、用一个,顺便把 pip 和依赖清单一次讲透
装什么好呢?还记得用 curl 查公网 IP 吗?那件事 Python 也能做;新建一个 api_demo.py:
import requests resp = requests.get("https://api.ipify.org?format=json") print(resp.json())requests 是 Python 世界最有名的第三方库之一,专门用来发网络请求——可以把它理解成 "代码版的 curl";跑跑看:
python3 api_demo.py结果不是 IP,而是一段报错:
ModuleNotFoundError: No module named 'requests'报错是线索(这句话会一直强调);它说得很直白:找不到 requests 这个模块——因为它不是标准库,Python 没自带,得先装
pip:装第三方库的工具
装 Python 第三方库的工具叫 pip——装 Python 时就一起装好了,就是后端世界的 npm(前端用 npm install 装过 anime.js,现在轮到 pip install);先确认自己在(zero-to-tech)环境里(提示符带着括号),然后:
pip install requests一条生存法则,从现在记起:装包之前,先瞄一眼提示符,确认(zero-to-tech)在——最常见的翻车就是忘了激活、把包装到了外面,回头一跑代码报 "找不到模块",人就懵了
看它滚动的输出——除了 requests 本身,还捎带装了 certifi、charset-normalizer、urllib3、idna 几个你没点名的:依赖还有依赖,npm 那边如此,pip 这边也一样
装完,问一个最关键的问题——它装到哪儿去了?看一眼:
pip show requestsName: requests Version: 2.34.2 Location: /Users/你的用户名/zero-to-tech/backend/.venv/lib/python3.x/site-packagesLocation 那行,路径指进了 .venv——正是刚建的那间 "项目专属的屋子":requests 只住进了这个项目,没装到全局环境,所以也不会和别的项目打架;前面讲了半天 venv 的道理,这一刻落到实处了(也可以敲 ls .venv/lib/python*/site-packages/,亲眼看到 requests 的目录躺在里面)
现在再跑一次 api_demo.py:
python3 api_demo.py{'ip': '114.86.123.45'}通了:我们用 Python 查到了自己的公网 IP——和用 curl 干的是同一件事,只不过这回是程序在调 API,正是那句 "API 是设计给计算机程序用的"(往后我们自己的后端,也可以像这样去调别人的 API)
眼尖的你可能发现:这回打印的{'ip': ...}是单引号,而刚才 first_json.py 打印的{"message": ...}是双引号,怎么不一样?因为它们其实是两种东西:first_json.py 里 json.dumps(...) 产出的是一段 JSON 文本(JSON 规定用双引号);而这里 resp.json() 直接把返回的 JSON 解析成了一个 Python 字典,打印字典时 Python 习惯用单引号;字典 ≈ JSON——这个对应关系以后天天见
requirements.txt:给依赖记一本账
现在冒出一个新问题:.venv 不进 Git(刚立的规矩),那别人拿到这个项目之后,怎么知道要装 requests?或者把代码拉到服务器上之后,该怎么安装依赖?
答案和前端一模一样:前端靠 package.json 记依赖,Python 靠 requirements.txt;生成它:
pip freeze > requirements.txtcat requirements.txt 看一眼:
certifi==2026.6.17 charset-normalizer==3.4.8 idna==3.18 requests==2.34.2 urllib3==2.7.0每个包一行,版本号钉得死死的(连那几个 "依赖的依赖" 也一并列上了);以后任何人拿到项目,一条命令就能装齐一模一样的环境:
pip install -r requirements.txt这就是后端版的 npm install;和 .venv 相反,requirements.txt 要进 Git——它是项目的一部分,得跟着代码走;到上服务器需要装依赖的时候,这份清单的价值就体现了
又凑齐一组 "角色对应",前端后端一一对上:
| 前端 | 后端 | 干的活 |
|---|---|---|
| npm | pip | 装第三方包 |
| node_modules/ | .venv/ | 装到哪儿(都不进 Git) |
| package.json | requirements.txt | 依赖清单(都进 Git) |