配置文件、网站接口、AI的回复,满世界都是JSON——今天你把它彻底看懂
一、你早就在见它了,只是不知道它叫JSON
先讲一个你肯定遇到过的场景。
你跟AI说:”帮我把这周的菜谱整理一下。”AI回复了一段话,里面是一份结构清晰的清单。你又说:”把这个存到文件里吧。”AI给你存好了。第二天你想让另一个程序读这份菜谱——比如做个采购清单工具——问题来了:
两个程序之间,怎么交接这份数据?
直接把Python的字典存进文件?别的语言(或者JavaScript、Java写的程序)可读不懂Python字典的格式。就像中国人说中文、法国人说法语,中间需要一种大家都认的通用语。
这门通用语,就叫JSON(读作”杰森”,全名JavaScript Object Notation)。你在生活里其实天天撞见它:
- 手机App的设置文件,存的就是JSON
- 网站从服务器拿天气、拿股票价格,传的就是JSON
- 你问AI问题,AI后端接口来回传的也是JSON
- 就连上个月你折腾的各种工具配置,八成也是JSON或它的亲戚
JSON长什么样?给你看一眼:
{
"名字": "小明",
"年龄": 28,
"会编程": true,
"技能": ["Python", "Excel", "做PPT"],
"地址": {
"城市": "沈阳",
"邮编": "110000"
}
}
盯着看五秒,你会发现一个惊人的事实:这不就是字典吗?对,JSON就是”长得像字典的通用数据格式”。花括号包着,键值对,冒号隔开——你第8篇就学过字典了,今天等于给老朋友换了个身份证。
那今天的新知识是什么?只有一个:json模块——Python自带的”JSON翻译官”,负责把JSON翻译成Python能懂的字典/列表,也能把Python的字典/列表翻译成JSON。两个函数的事,五分钟包会。
二、新招就一个:json模块的两把刷子
json模块是Python自带的(跟csv一样,不用安装),两把刷子对应两个方向:
| 方向 | 函数 | 记忆口诀 |
|---|
|——|——|———|
| JSON文本 → Python字典 | json.loads(文本) |
loads = load string(读字符串) |
|---|---|---|
| Python字典 → JSON文本 | json.dumps(字典) |
dumps = dump string(写字符串) |
注意两个函数名后面都带个s,带s的版本处理的是文本(字符串)。先看翻译效果:
import json
# 翻译进来:JSON文本 -> Python字典
天气文本 = '{"城市": "沈阳", "温度": 15, "天气": "晴", "风力": 3}'
天气 = json.loads(天气文本)
print(天气["城市"]) # 沈阳
print(type(天气)) # 已经是正经字典了
print(天气.get("湿度", "没报")) # 没报 字典的招全能用
# 翻译出去:Python字典 -> JSON文本
购物车 = {"苹果": 3, "牛奶": 2, "鸡蛋": 12}
文本 = json.dumps(购物车, ensure_ascii=False)
print(文本) # {"苹果": 3, "牛奶": 2, "鸡蛋": 12}
两个函数,一个进一个出,今天全部的新知识就讲完了。剩下的都是”怎么用得顺手”。
不过json.dumps身上有个参数必须现在就记住:ensure_ascii=False。不加它,中文会被翻译成u82f9u679c这种天书(那是Unicode编码,机器认得人认不得)。加上它,中文原样保留。这个参数从今天起每次dumps都带上,当肌肉记忆。
想让JSON文本好看点(给人看、存配置文件),再加一个indent=2:
漂亮文本 = json.dumps(购物车, ensure_ascii=False, indent=2)
print(漂亮文本)
# {
# "苹果": 3,
# "牛奶": 2,
# "鸡蛋": 12
# }
先跟AI热个身,走一遍今天的学习姿势(跟AI说需求 → 读懂 → 改进):
我有一个Python字典装着一个人的信息(名字、年龄、爱好列表、地址字典),帮我把它转成JSON文本打印出来,中文要正常显示,格式要有缩进;再把这个JSON文本转回字典打印出来,验证能还原。
拿到代码先别跑,读一遍:dumps是出去、loads是进来,方向对不对?跑通之后想”改进”——比如”爱好列表我想加一个再存”。这个来回翻译的流程今天会走很多遍,走熟了JSON就算拿下了。
三、JSON和字典的三个小区别(翻译官的脾气)
JSON看着像字典,但它不是字典,翻译的时候有几个小脾气,提前认识一下:
脾气1:JSON的键必须是双引号的文本。 Python字典的键可以用单引号甚至数字,JSON只认双引号:
import json
# 下面这行会报错!JSON里用了单引号
# json.loads("{'城市': '沈阳'}") # ❌ json.decoder.JSONDecodeError
print(json.loads('{"城市": "沈阳"}')) # ✅ 双引号才是JSON
脾气2:JSON只有六种数据类型。 文本(字符串)、数字、true/false、null(空值)、数组(对应Python列表)、对象(对应Python字典)。Python的元组、集合、日期对象,JSON都不认识,存之前得先转换。
脾气3:翻译会”丢细节”。 元组进去,出来变列表;键是数字的字典,出来键变文本。不过日常用完全无感,知道有这回事就行:
import json
data = {"结果": (1, 2, 3)}
回来 = json.loads(json.dumps(data))
print(回来) # {'结果': [1, 2, 3]}
print(type(回来["结果"])) # 元组进去,列表出来
一句话总结:JSON是”通用语”,字典是”母语”,json模块是同声传译。同声传译偶尔丢几个语气词,但意思不走样。
四、实战:存档和读档——给程序一个”记忆”
光在内存里翻译来翻译去没意思,JSON真正的威力是存进文件——让你的程序有记忆。这里要请出第9篇的老朋友open,配合json就齐活了:
import json
# ---- 存档:字典 -> 文件 ----
游戏存档 = {
"玩家": "小明",
"等级": 23,
"金币": 1580,
"装备": ["铁剑", "皮甲", "治疗药水x5"],
"位置": {"地图": "黑森林", "坐标": [120, 45]}
}
with open("存档.json", "w", encoding="utf-8") as f:
json.dump(游戏存档, f, ensure_ascii=False, indent=2)
print("存档成功!")
注意这里的函数不带s了:json.dump(数据, 文件)——不带s的版本直接写给文件,所以第二个参数是文件对象。口诀升级:
loads/dumps:带s处理string(文本)load/dump:不带s,直接对文件干活
# ---- 读档:文件 -> 字典 ----
import json
with open("存档.json", "r", encoding="utf-8") as f:
读回来的存档 = json.load(f)
print(读回来的存档["玩家"]) # 小明
print(读回来的存档["装备"][0]) # 铁剑
print(读回来的存档["位置"]["坐标"]) # [120, 45]
嵌套再深也不怕——字典里套列表、列表里套字典,一层层用[]往下取就行。现在把学到的串起来做一个完整的每日待办存档器,体会”存档+读档”的完整闭环:
我想做一个每日待办的小工具:启动时如果待办.json存在就自动读出来显示;可以添加新任务、把任务标记为完成、显示所有任务;每次改动后自动存回待办.json,下次打开还在。帮我写这个程序,要能处理第一次运行没有文件的情况。
import json
import os
文件名 = "待办.json"
# ---- 启动:有存档就读,没有就给个空本子 ----
if os.path.exists(文件名):
with open(文件名, "r", encoding="utf-8") as f:
待办清单 = json.load(f)
print(f"读档成功,你有 {len(待办清单)} 条待办。")
else:
待办清单 = []
print("第一次运行,给你开个新本子。")
def 存档():
with open(文件名, "w", encoding="utf-8") as f:
json.dump(待办清单, f, ensure_ascii=False, indent=2)
def 显示():
if not 待办清单:
print("(空空如也,加点任务吧)")
return
for i, 任务 in enumerate(待办清单, 1):
状态 = "✅" if 任务["完成"] else "⬜"
print(f"{i}. {状态} {任务['内容']}")
while True:
print("n--- 待办存档器 ---")
print("1. 加任务 2. 完成任务 3. 看全部 0. 退出")
选择 = input("选:").strip()
if 选择 == "1":
内容 = input("任务内容:").strip()
if 内容:
待办清单.append({"内容": 内容, "完成": False})
存档()
print("已加并存档。")
elif 选择 == "2":
显示()
try:
序号 = int(input("完成第几条:")) - 1
待办清单[序号]["完成"] = True
存档()
print("已标完成并存档。")
except (ValueError, IndexError):
print("序号不对,白干。")
elif 选择 == "3":
显示()
elif 选择 == "0":
存档()
print("存档退出,下次见。")
break
跑一遍:加两条任务 → 退出 → 再启动,任务还在。这就是JSON给你程序的记忆——关机重启数据不丢,比第9篇直接存文本强的地方在于:存的是结构,读回来还是字典和列表,程序能直接接着用。
读代码时重点看这条”数据流”:input拿到文本 → 变成字典{"内容":…, "完成":…} → 挂进列表 → json.dump写进文件;下次启动json.load读回来 → 又是那个列表。数据在程序和文件之间来回都是”结构”,没有一次需要手工拆字符串——这就是JSON比按行存文本强的地方。
五、真实场景:跟AI交换数据
JSON最出彩的地方是程序和外界说话。你可能不知道,你每天用AI的方式,背后就是JSON在跑腿。看这个模拟场景——假设一个”数据包”从外面传来:
import json
# 模拟从网上/AI那儿收到的一段JSON(其实是一段文本)
收到的文本 = '''
{
"城市": "沈阳",
"今天": {"天气": "晴", "高温": 22, "低温": 12},
"未来三天": [
{"日期": "10-04", "天气": "多云", "高温": 21},
{"日期": "10-05", "天气": "小雨", "高温": 18},
{"日期": "10-06", "天气": "晴", "高温": 20}
]
}
'''
数据 = json.loads(收到的文本)
print(f"{数据['城市']}今天{数据['今天']['天气']},{数据['今天']['低温']}~{数据['今天']['高温']}°C")
for 一天 in 数据["未来三天"]:
print(f"{一天['日期']}:{一天['天气']},最高{一天['高温']}°C")
# 挑出要出门的那天,整理成一个小JSON发给别的程序
出门建议 = {"日期": "10-05", "带伞": True, "加衣": True}
print(json.dumps(出门建议, ensure_ascii=False))
以后你学第37篇发网络请求时,拿到的天气、股票数据全是这种JSON文本,json.loads一翻译就能用。今天这一步,是给未来所有”跟外界打交道”的程序打地基。
六、三个必踩的坑(先打疫苗)
坑1:忘了ensure_ascii=False,满屏天书。 存出来的JSON变成"u6c88u9633",人看不懂还以为程序坏了。记住:给人看的JSON,ensure_ascii=False必带。这是今天最高频的坑,没有之一。
坑2:手写JSON忘了双引号、多了尾逗号。 JSON是给机器读的,语法极其死板:键必须双引号、最后一项不能有逗号。你手写config.json时写成下面这样,程序直接崩:
import json
坏文本 = '{"名字": "小明", "爱好": ["读书",],}' # 尾逗号 + 花括号前多逗号
try:
json.loads(坏文本)
except json.JSONDecodeError as e:
print("JSON格式错了:", e) # Expecting property name enclosed in double quotes
报错别慌,JSONDecodeError的信息里带行号和列号,照着去改就行。防坑姿势:JSON文件尽量让程序生成,少手写;非要手写,改完跑一行json.load验证一下。
坑3:读文件忘了encoding="utf-8"。 第9篇的老坑在JSON这儿照样发作——Windows上不写编码,带中文的JSON读出来乱码或直接报错。open后面永远跟上encoding="utf-8",当成本能。
顺带一个疫苗:json.load(f)读出来的一律是”纯JSON世界”的类型——字典、列表、字符串、数字、True/False/None。想存日期?存成文本"2026-10-03",用的时候再转换。JSON不认识日期类型,这是设计如此,不是bug。
七、跟AI协作的正确姿势(JSON特供)
JSON是AI天天用的格式,跟它协作有三个要点:
- 描述数据的”形状”。”帮我存个JSON”等于没说;”我有一个字典,键是姓名,值是又一个字典(含年龄、城市),帮我转成带缩进的JSON存进文件,中文正常显示”——AI代码一次到位。说清嵌套结构,AI就不猜
- 读懂”翻译方向”。AI给的代码里出现
loads,就想:这是把外面的文本翻进来;出现dumps,就是把内存里的结构翻出去。方向看懂了,代码就不会跑反 - 让AI帮你验证。拿到AI生成的JSON文本,丢回给它说”帮我验证这个JSON格式对不对,顺便转成字典打印”。格式错误当场现形,比程序跑一半崩掉强
另外送你一个高频句式,以后天天用:”把结果存成JSON文件,下次启动时自动读取“——这一句话能让AI给你写出带记忆的程序。
八、今日小练习
练习1:个人名片存档器
做一个”名片程序”:输入姓名、职业、爱好(逗号分隔的文本),程序把它整理成{"姓名":…, "职业":…, "爱好":[…]}存进名片.json;再写一段读取代码,把名片.json读回来打印成一段自我介绍。(提示:爱好用爱好文本.split(",")切成列表;存的时候记得ensure_ascii=False。读回来后用f-string拼介绍,列表用"、".join()连接成人话。)
练习2:多次存档的”日记本”
把第四节的待办存档器改成日记本:每次写一条日记(日期+内容),追加进日记.json的列表里,启动时把所有日记按条打印。(提示:读档后拿到的是列表,用append加新条目再整本dump回去——JSON存的是整个结构,”追加”其实是”读出来、加上、再存回去”。日期不会写?from datetime import date,str(date.today())就是今天。)
练习3:JSON数据体检器
写一个工具:读任意一个.json文件,输出它的”体检报告”——顶层是字典还是列表、有几个键/元素、每个键对应的值是什么类型、嵌套最深有几层。(提示:判断类型用isinstance(值, dict)和isinstance(值, list);”算深度”适合让AI帮你写一个递归函数——看不懂递归没关系,先会用,第100篇之后会专门讲它。这题就是让你练”把需求说给AI听”。)
写在后面:你已经会”数据通用语”了
盘点一下今天到手的东西:json.loads翻进来、json.dumps翻出去、json.load/dump直通文件、ensure_ascii=False保中文、indent排版——一共五个知识点,核心就是两个方向的翻译。
从今天起,你的程序不再是一座孤岛:数据能存成全世界程序都认的格式,能发给别的工具、发给AI、发给未来的你。你上个月学的字典和列表,今天突然”国际化”了。
下一篇我们把JSON用到它最经典的地盘——配置文件。程序的设置项(开关、路径、默认值)不该硬写在代码里,而该放进一个JSON文件,改设置不用改代码。这是”专业程序”和”玩具程序”的分水岭之一。
下篇预告
第二十八篇:配置文件管理——为什么专业程序的设置都放在单独的文件里?怎么做一个”改配置不改代码”的程序?没配置文件时自动创建默认配置?下一篇见。
发表回复