跳到正文
效率工具实用笔记关于本站
表格与数据

JSON文本与Python字典有什么区别:用loads和dumps转换

约 7 分钟阅读AI 辅助整理

JSON字符串是文本,Python字典是内存对象,两者靠json.loads和json.dumps互转。本文用自建示例说明中文、布尔值、null的对照关系,以及格式错误怎么定位。

本文要点

  1. 这是初学者最容易困惑的一处

  2. JSON和Python在布尔值与空值上的写法不同,这是loads和dumps转换时最需要记住的对照关系

  3. JSON对象的键在规范里始终是字符串类型

JSON文本与Python字典有什么区别:用loads和dumps转换的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

先分清:一个是文本,一个是内存里的对象

如果你手里有一段花括号包起来的内容,先要判断它是JSON字符串还是Python字典,因为两者的操作方式完全不同。

JSON是一种轻量级数据交换格式,由RFC 7159和ECMA-404规定。在Python里,JSON文本表现为str(字符串),字典表现为dict(字典对象)。字符串是文本,你可以打印、拼接、写入文件;字典是内存中的对象,你可以用键取值、增删键值对。

转换方向只有两个:

- json.loads(s):把JSON字符串解析成Python对象。

- json.dumps(obj):把Python对象序列化成JSON字符串。

本文只讨论内存中JSON字符串和字典的互转,不涉及文件读取。下面所有示例都是自建的练习数据,不是对真实数据的测试记录。

一个容易混淆的点:JSON里的object指花括号包起来的数据,类似Python字典;但Python里所有值都是对象,两个“对象”含义不同。

中文字符串:dumps默认转义,loads自动还原

这是初学者最容易困惑的一处。用dumps转换含中文的字典时,默认输出会把非ASCII字符转义成\uXXXX形式。

import json

d = {"name": "示例项目", "city": "北京"}
s = json.dumps(d)
print(s)

输出里中文会变成转义序列,因为ensure_ascii默认为True,输出保证只含可打印ASCII字符。如果你希望中文原样显示,可以设置ensure_ascii=False:

s2 = json.dumps(d, ensure_ascii=False)
print(s2)

这次输出里中文保持原样。

反向操作时,loads能正确还原这两种写法:

json.loads(s)   # 转义写法
json.loads(s2)  # 原样写法

两者解析结果相同。也就是说,转义只是文本表示方式,不影响解析后的内容。

需要提醒:ensure_ascii=False时,除引号、反斜杠和U+0000到U+001F控制字符外,其余字符原样输出。

布尔值和null:JSON小写,Python首字母大写

JSON和Python在布尔值与空值上的写法不同,这是loads和dumps转换时最需要记住的对照关系。

按json模块的解码转换表:

- JSON的true对应Python的True

- JSON的false对应Python的False

- JSON的null对应Python的None

编码方向则相反:Python的True、False、None分别输出为true、false、null。

自建示例:

import json

s = '{"active": true, "deleted": false, "note": null}'
d = json.loads(s)
print(d)

解析后d里的值分别是True、False、None。再转回去:

print(json.dumps(d))

输出里又变回true、false、null。

关键点:JSON文本里不能写True、False、None,Python字典里也不该把true、false、null当变量名。写错方向会直接报错。

字典键会变成字符串:往返转换可能不相等

JSON对象的键在规范里始终是字符串类型。当Python字典转成JSON时,所有键都会被转成字符串。

这带来一个后果:如果原字典用了非字符串键,转换后再转回来,结果可能和原字典不相等。文档明确写了这一点:loads(dumps(x)) != x,当x含非字符串键时成立。

自建示例:

import json

x = {1: "a", 2: "b"}
s = json.dumps(x)
print(s)
print(json.loads(s))

转回后键变成字符串"1"、"2",和原来的整数键1、2不相等。

另外,sort_keys=True会先排序键再转成字符串,所以数字键按数值排序,而不是按字符串表示排序。

格式错误怎么定位:用JSONDecodeError的三个属性

loads遇到不合法的JSON文档时,会抛出JSONDecodeError,它是ValueError的子类。

这个异常带有几个属性,能帮你定位问题:

- msg:未格式化的错误消息

- doc:正在解析的JSON文档

- pos:解析失败的起始索引

- lineno:pos对应的行号

- colno:pos对应的列号

自建示例,故意写一个格式错误的字符串:

import json

bad = '{"name": "示例", }'
try:
    json.loads(bad)
except json.JSONDecodeError as e:
    print(e.msg)
    print(e.lineno, e.colno)

这里末尾多了一个逗号,属于常见错误。异常会告诉你出错的位置。

其他常见格式错误包括:用单引号代替双引号、键没有加引号、括号不配对。这些都会触发JSONDecodeError。

两个容易踩的边界:重复键和特殊浮点值

这两点资料里有明确说明,初学者容易忽略。

第一,重复键。RFC规定JSON对象的名称应当唯一,但没规定重复时怎么处理。默认情况下,json模块不报错,只保留最后一个键值对:

import json

weird = '{"x": 1, "x": 2, "x": 3}'
print(json.loads(weird))

结果是{'x': 3}。如果你需要改变这个行为,可以用object_pairs_hook参数。

第二,Infinity和NaN。RFC不允许表示无穷或NaN数值,但默认情况下json模块接受并输出它们:

import json

print(json.dumps(float('nan')))
print(json.loads('NaN'))

输出分别是NaN和nan。这些结果不是合法JSON。序列化时可以用allow_nan=False改为抛ValueError;反序列化时可以用parse_constant参数改变行为。

这两点说明:json模块默认设置下并不严格符合RFC,实现了一些JavaScript合法但JSON不合法的扩展。

安全提醒与适用范围

解析来自不可信来源的JSON数据时要谨慎。文档警告:恶意JSON字符串可能导致解码器消耗大量CPU和内存资源,建议限制待解析数据的大小。

本文只讨论内存中JSON字符串和字典的互转,不涉及文件读取、网络请求或数据持久化。所有示例均为自建练习数据,不是实测记录。

最后一点:本文的对照表和示例是编辑整理的,用于帮助理解转换关系,不替代官方文档。具体参数行为以你所使用Python版本的官方文档为准。

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回表格与数据 →