19.2. json — JSON 编码器和解码器 — Python 文档
19.2. json — JSON 编码器和解码器
源代码: :source:`Lib/json/__init__.py`
JSON(JavaScript 对象表示法),由 RFC 7159(废弃 RFC 4627)和[ X136X]ECMA-404 是一种轻量级数据交换格式,其灵感来自 JavaScript 对象字面量语法(尽管它不是 JavaScript 1 的严格子集)。
json 公开了标准库 marshal 和 pickle 模块的用户熟悉的 API。
编码基本的 Python 对象层次结构:
>>> import json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print(json.dumps("\"foo\bar"))
"\"foo\bar"
>>> print(json.dumps('\u1234'))
"\u1234"
>>> print(json.dumps('\\'))
"\\"
>>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
{"a": 0, "b": 0, "c": 0}
>>> from io import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'
紧凑编码:
>>> import json
>>> json.dumps([1, 2, 3, {'4': 5, '6': 7}], separators=(',', ':'))
'[1,2,3,{"4":5,"6":7}]'
漂亮的印刷:
>>> import json
>>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4))
{
"4": 5,
"6": 7
}
解码JSON:
>>> import json
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
['foo', {'bar': ['baz', None, 1.0, 2]}]
>>> json.loads('"\\"foo\\bar"')
'"foo\x08ar'
>>> from io import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)
['streaming API']
专门的 JSON 对象解码:
>>> import json
>>> def as_complex(dct):
... if '__complex__' in dct:
... return complex(dct['real'], dct['imag'])
... return dct
...
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
... object_hook=as_complex)
(1+2j)
>>> import decimal
>>> json.loads('1.1', parse_float=decimal.Decimal)
Decimal('1.1')
扩展 JSONEncoder:
>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
... def default(self, obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... # Let the base class default method raise the TypeError
... return json.JSONEncoder.default(self, obj)
...
>>> json.dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[2.0', ', 1.0', ']']
使用 shell 中的 json.tool 来验证和漂亮打印:
$ echo '{"json":"obj"}' | python -m json.tool
{
"json": "obj"
}
$ echo '{1.2:3.4}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
有关详细文档,请参阅 命令行界面 。
笔记
JSON 是 YAML 1.2 的子集。 此模块的默认设置(特别是默认的 separators 值)生成的 JSON 也是 YAML 1.0 和 1.1 的子集。 因此,该模块也可以用作 YAML 序列化程序。
19.2.1. 基本用法
- json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
使用此 转换表将 obj 作为 JSON 格式的流序列化为 fp(一个
.write()
-支持 类文件对象 )[ X147X]。如果 skipkeys 为真(默认值:
False
),则 dict 键不是基本类型 (str, int, ]float, bool,None
) 将被跳过而不是引发 TypeError。json 模块总是产生 str 对象,而不是 bytes 对象。 因此,
fp.write()
必须支持 [X34X]str 输入。如果 ensure_ascii 为真(默认值),则输出保证所有传入的非 ASCII 字符都被转义。 如果 ensure_ascii 为假,这些字符将按原样输出。
如果 check_circular 为 false(默认值:
True
),则将跳过容器类型的循环引用检查,循环引用将导致 OverflowError(或更糟)。如果 allow_nan 为 false(默认值:
True
),那么序列化超出范围 float 值(nan
、inf
、-inf
) 严格遵守 JSON 规范。 如果 allow_nan 为真,则将使用它们的 JavaScript 等效项(NaN
、Infinity
、-Infinity
)。如果 indent 是非负整数或字符串,则 JSON 数组元素和对象成员将使用该缩进级别进行漂亮打印。 缩进级别 0、负数或
""
只会插入换行符。None
(默认)选择最紧凑的表示。 使用正整数缩进每级缩进多少个空格。 如果 indent 是一个字符串(例如"\t"
),则该字符串用于缩进每个级别。在 3.2 版中更改: 除了整数外,还允许 缩进 的字符串。
如果指定,separators 应该是一个
(item_separator, key_separator)
元组。 如果 indent 为None
,否则默认为(', ', ': ')
,否则为(',', ': ')
。 要获得最紧凑的 JSON 表示,您应该指定(',', ':')
以消除空格。3.4 版更改: 如果 indent 不是
None
,则默认使用(',', ': ')
。如果指定,default 应该是一个函数,该函数为无法序列化的对象调用。 它应该返回对象的 JSON 可编码版本或引发 TypeError。 如果未指定,则会引发 TypeError。
如果 sort_keys 为真(默认值:
False
),则字典的输出将按键排序。使用自定义 JSONEncoder 子类(例如 一种覆盖
default()
方法以序列化其他类型的方法),用 cls kwarg 指定它; 否则使用 JSONEncoder。3.6 版更改: 所有可选参数现在都是 仅关键字 。
- json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
使用此 转换表 将 obj 序列化为 JSON 格式的 str。 这些参数的含义与 dump() 中的含义相同。
笔记
JSON 的键/值对中的键始终是 str 类型。 当字典转换为 JSON 时,字典的所有键都被强制转换为字符串。 因此,如果将字典转换为 JSON,然后再转换回字典,则该字典可能不等于原始字典。 也就是说,如果 x 具有非字符串键,则为
loads(dumps(x)) != x
。
- json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
使用此 转换将 fp(支持
.read()
的 文本文件 或 二进制文件 包含一个 JSON 文档)反序列化为 Python 对象表。object_hook 是一个可选函数,将使用任何对象文字解码的结果(dict)调用。 将使用 object_hook 的返回值代替 dict。 此功能可用于实现自定义解码器(例如 JSON-RPC 类提示)。
object_pairs_hook 是一个可选函数,它将使用任何对象字面量的结果被调用,该结果是用有序的对列表解码的。 将使用 object_pairs_hook 的返回值代替 dict。 此功能可用于实现依赖于键值对解码顺序的自定义解码器(例如,collections.OrderedDict() 将记住插入的顺序)。 如果还定义了 object_hook,则 object_pairs_hook 优先。
3.1 版更改: 添加了对 object_pairs_hook 的支持。
parse_float,如果指定,将使用每个要解码的 JSON 浮点数的字符串调用。 默认情况下,这相当于
float(num_str)
。 这可用于为 JSON 浮点数使用另一种数据类型或解析器(例如 十进制。十进制)。parse_int,如果指定,将使用每个要解码的 JSON int 的字符串调用。 默认情况下,这相当于
int(num_str)
。 这可用于对 JSON 整数使用另一种数据类型或解析器(例如 浮动)。parse_constant,如果指定,将使用以下字符串之一调用:
'-Infinity'
、'Infinity'
、'NaN'
。 如果遇到无效的 JSON 数字,这可用于引发异常。3.1 版更改:parse_constant 不再在 'null'、'true'、'false' 上调用。
要使用自定义 JSONDecoder 子类,请使用
cls
kwarg 指定它; 否则使用 JSONDecoder。 额外的关键字参数将传递给类的构造函数。如果反序列化的数据不是有效的 JSON 文档,则会引发 JSONDecodeError。
3.6 版更改: 所有可选参数现在都是 仅关键字 。
在 3.6 版更改:fp 现在可以是 二进制文件 。 输入编码应为 UTF-8、UTF-16 或 UTF-32。
- json.loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
使用此 转换表将 s(包含 JSON 文档的 str、bytes 或 bytearray 实例)反序列化为 Python 对象。
其他参数与 load() 中的含义相同,除了 encoding 被忽略和弃用。
如果反序列化的数据不是有效的 JSON 文档,则会引发 JSONDecodeError。
19.2.2. 编码器和解码器
- class json.JSONDecoder(*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None)
简单的 JSON 解码器。
默认情况下在解码中执行以下翻译:
JSON
Python
目的
字典
大批
列表
细绳
字符串
数字(整数)
整数
数量(实数)
漂浮
真的
真的
错误的
错误的
无效的
没有任何
它还将
NaN
、Infinity
和-Infinity
理解为它们对应的float
值,这在 JSON 规范之外。object_hook,如果指定,将使用解码的每个 JSON 对象的结果调用,其返回值将用于代替给定的 dict。 这可用于提供自定义反序列化(例如 以支持 JSON-RPC 类提示)。
object_pairs_hook,如果指定,将使用每个 JSON 对象的结果进行调用,这些 JSON 对象是用有序的对列表解码的。 将使用 object_pairs_hook 的返回值代替 dict。 此功能可用于实现依赖于键值对解码顺序的自定义解码器(例如,collections.OrderedDict() 将记住插入的顺序)。 如果还定义了 object_hook,则 object_pairs_hook 优先。
3.1 版更改: 添加了对 object_pairs_hook 的支持。
parse_float,如果指定,将使用每个要解码的 JSON 浮点数的字符串调用。 默认情况下,这相当于
float(num_str)
。 这可用于为 JSON 浮点数使用另一种数据类型或解析器(例如 十进制。十进制)。parse_int,如果指定,将使用每个要解码的 JSON int 的字符串调用。 默认情况下,这相当于
int(num_str)
。 这可用于对 JSON 整数使用另一种数据类型或解析器(例如 浮动)。parse_constant,如果指定,将使用以下字符串之一调用:
'-Infinity'
、'Infinity'
、'NaN'
。 如果遇到无效的 JSON 数字,这可用于引发异常。如果 strict 为 false(
True
是默认值),则字符串中将允许使用控制字符。 本上下文中的控制字符是字符代码在 0-31 范围内的字符,包括'\t'
(制表符)、'\n'
、'\r'
和'\0'
。如果反序列化的数据不是有效的 JSON 文档,则会引发 JSONDecodeError。
3.6 版更改: 所有参数现在都是 仅关键字 。
- decode(s)
返回 s(包含 JSON 文档的 str 实例)的 Python 表示。
如果给定的 JSON 文档无效,将引发 JSONDecodeError。
- raw_decode(s)
从 s(以 JSON 文档开头的 str)解码 JSON 文档,并返回 Python 表示的 2 元组和 s 中的索引,其中文件结束。
这可用于从末尾可能包含无关数据的字符串解码 JSON 文档。
- class json.JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)
用于 Python 数据结构的可扩展 JSON 编码器。
默认支持以下对象和类型:
Python
JSON
字典
目的
列表,元组
大批
字符串
细绳
int、float、int 和 float 派生的枚举
数字
真的
真的
错误的
错误的
没有任何
无效的
3.4 版更改: 添加了对 int 和 float 派生 Enum 类的支持。
为了扩展它以识别其他对象,子类化并使用另一个方法实现 default() 方法,如果可能,该方法返回
o
的可序列化对象,否则它应该调用超类实现(引发 类型错误 )。如果 skipkeys 为 false(默认值),则尝试编码不是 str、int 的键是 TypeError, 浮动或
None
。 如果 skipkeys 为真,则简单地跳过此类项目。如果 ensure_ascii 为真(默认值),则输出保证所有传入的非 ASCII 字符都被转义。 如果 ensure_ascii 为假,这些字符将按原样输出。
如果 check_circular 为 true(默认值),则在编码期间将检查列表、字典和自定义编码对象的循环引用,以防止无限递归(这会导致 OverflowError) . 否则,不会进行此类检查。
如果 allow_nan 为 true(默认值),则
NaN
、Infinity
和-Infinity
将被编码为这样。 此行为不符合 JSON 规范,但与大多数基于 JavaScript 的编码器和解码器一致。 否则,编码此类浮点数将是 ValueError。如果 sort_keys 为真(默认:
False
),则字典的输出将按键排序; 这对于回归测试很有用,以确保可以每天比较 JSON 序列化。如果 indent 是非负整数或字符串,则 JSON 数组元素和对象成员将使用该缩进级别进行漂亮打印。 缩进级别 0、负数或
""
只会插入换行符。None
(默认)选择最紧凑的表示。 使用正整数缩进每级缩进多少个空格。 如果 indent 是一个字符串(例如"\t"
),则该字符串用于缩进每个级别。在 3.2 版中更改: 除了整数外,还允许 缩进 的字符串。
如果指定,separators 应该是一个
(item_separator, key_separator)
元组。 如果 indent 为None
,否则默认为(', ', ': ')
,否则为(',', ': ')
。 要获得最紧凑的 JSON 表示,您应该指定(',', ':')
以消除空格。3.4 版更改: 如果 indent 不是
None
,则默认使用(',', ': ')
。如果指定,default 应该是一个函数,该函数为无法序列化的对象调用。 它应该返回对象的 JSON 可编码版本或引发 TypeError。 如果未指定,则会引发 TypeError。
3.6 版更改: 所有参数现在都是 仅关键字 。
- default(o)
在子类中实现此方法,使其返回 o 的可序列化对象,或调用基本实现(引发 TypeError)。
例如,要支持任意迭代器,您可以像这样实现默认值:
def default(self, o): try: iterable = iter(o) except TypeError: pass else: return list(iterable) # Let the base class default method raise the TypeError return json.JSONEncoder.default(self, o)
- encode(o)
返回 Python 数据结构的 JSON 字符串表示形式,o。 例如:
>>> json.JSONEncoder().encode({"foo": ["bar", "baz"]}) '{"foo": ["bar", "baz"]}'
- iterencode(o)
对给定的对象 o 进行编码,并生成每个可用的字符串表示。 例如:
for chunk in json.JSONEncoder().iterencode(bigobject): mysocket.write(chunk)
19.2.3. 例外
- exception json.JSONDecodeError(msg, doc, pos)
ValueError 的子类,具有以下附加属性:
- msg
未格式化的错误消息。
- doc
正在解析的 JSON 文档。
- pos
doc 解析失败的起始索引。
- lineno
对应于 pos 的行。
- colno
对应于 pos 的列。
3.5 版中的新功能。
19.2.4. 标准合规性和互操作性
JSON 格式由 RFC 7159 和 ECMA-404 指定。 本节详细介绍了该模块与 RFC 的合规性级别。 为简单起见,不考虑 JSONEncoder 和 JSONDecoder 子类以及明确提到的参数以外的参数。
该模块不严格遵守 RFC,实现了一些有效的 JavaScript 但不是有效的 JSON 的扩展。 特别是:
- 无限和 NaN 数值被接受并输出;
- 接受对象内的重复名称,并且仅使用最后一个名称-值对的值。
由于 RFC 允许符合 RFC 的解析器接受不符合 RFC 的输入文本,因此该模块的解串器在默认设置下在技术上符合 RFC。
19.2.4.1. 字符编码
RFC 要求使用 UTF-8、UTF-16 或 UTF-32 表示 JSON,其中 UTF-8 是最大互操作性的推荐默认值。
根据 RFC 的允许,虽然不是必需的,但该模块的序列化程序默认设置 ensure_ascii=True,从而对输出进行转义,以便结果字符串仅包含 ASCII 字符。
除了 ensure_ascii 参数之外,这个模块是根据 Python 对象和 Unicode 字符串 之间的转换严格定义的,因此不直接解决字符编码问题。
RFC 禁止在 JSON 文本的开头添加字节顺序标记 (BOM),并且此模块的序列化程序不会向其输出添加 BOM。 RFC 允许但不要求 JSON 反序列化器忽略其输入中的初始 BOM。 当存在初始 BOM 时,此模块的解串器会引发 ValueError。
RFC 没有明确禁止包含与有效 Unicode 字符不对应的字节序列的 JSON 字符串(例如 未配对的 UTF-16 代理),但它确实指出它们可能会导致互操作性问题。 默认情况下,此模块接受并输出(当存在于原始 str 中时)此类序列的代码点。
19.2.4.2. 无限和 NaN 数值
RFC 不允许表示无限或 NaN 数值。 尽管如此,默认情况下,该模块接受并输出 Infinity
、-Infinity
和 NaN
,就好像它们是有效的 JSON 数字文字值一样:
>>> # Neither of these calls raises an exception, but the results are not valid JSON
>>> json.dumps(float('-inf'))
'-Infinity'
>>> json.dumps(float('nan'))
'NaN'
>>> # Same when deserializing
>>> json.loads('-Infinity')
-inf
>>> json.loads('NaN')
nan
在序列化程序中,allow_nan 参数可用于更改此行为。 在解串器中,parse_constant 参数可用于更改此行为。
19.2.4.3. 对象内的重复名称
RFC 指定 JSON 对象中的名称应该是唯一的,但没有强制要求如何处理 JSON 对象中的重复名称。 默认情况下,此模块不会引发异常; 相反,它会忽略给定名称的最后一个名称-值对以外的所有内容:
>>> weird_json = '{"x": 1, "x": 2, "x": 3}'
>>> json.loads(weird_json)
{'x': 3}
object_pairs_hook 参数可用于更改此行为。
19.2.4.4. 顶级非对象、非数组值
由过时的 RFC 4627 指定的旧版本 JSON 要求 JSON 文本的顶级值必须是 JSON 对象或数组(Python dict ] 或 list),并且不能是 JSON 空值、布尔值、数字或字符串值。 RFC 7159 删除了该限制,该模块没有也从未在其序列化器或解串器中实现该限制。
无论如何,为了获得最大的互操作性,您可能希望自己自愿遵守限制。
19.2.4.5. 实施限制
一些 JSON 反序列化器实现可能会在以下方面设置限制:
- 接受的 JSON 文本的大小
- JSON 对象和数组的最大嵌套级别
- JSON 数字的范围和精度
- JSON 字符串的内容和最大长度
除了相关 Python 数据类型本身或 Python 解释器本身的限制之外,该模块不会强加任何此类限制。
序列化为 JSON 时,请注意可能使用 JSON 的应用程序中的任何此类限制。 特别是,通常将 JSON 数字反序列化为 IEEE 754 双精度数字,因此受到该表示的范围和精度限制。 这在序列化极大量级的 Python int 值时,或在序列化“奇异”数字类型(如 decimal.Decimal)的实例时尤其重要。
19.2.5. 命令行界面
源代码: :source:`Lib/json/tool.py`
json.tool 模块提供了一个简单的命令行界面来验证和漂亮地打印 JSON 对象。
如果未指定可选的 infile
和 outfile
参数,将分别使用 sys.stdin 和 sys.stdout:
$ echo '{"json": "obj"}' | python -m json.tool
{
"json": "obj"
}
$ echo '{1.2:3.4}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
3.5 版更改: 输出现在与输入的顺序相同。 使用 --sort-keys 选项按键按字母顺序对字典的输出进行排序。
19.2.5.1. 命令行选项
- infile
要验证或漂亮打印的 JSON 文件:
$ python -m json.tool mp_films.json [ { "title": "And Now for Something Completely Different", "year": 1971 }, { "title": "Monty Python and the Holy Grail", "year": 1975 } ]
如果未指定 infile,则从 sys.stdin 读取。
- outfile
- 将 infile 的输出写入给定的 outfile。 否则,将其写入 sys.stdout。
- --sort-keys
按键按字母顺序对字典的输出进行排序。
3.5 版中的新功能。
- -h, --help
- 显示帮助信息。
脚注
- 1
- 如 RFC 7159 勘误表中所述,JSON 允许字符串中的文字 U+2028 (LINE SEPARATOR) 和 U+2029 (PARAGRAPH SEPARATOR) 字符,而 JavaScript(从 ECMAScript Edition 5.1 开始)则不允许。