json
— JSON 编码器和解码器¶
源代码: Lib/json/__init__.py
JSON(JavaScript 对象表示法),由 RFC 7159(已取代 RFC 4627)和 ECMA-404 规定,是一种轻量级数据交换格式,其灵感来自 JavaScript 对象字面量语法(尽管它不是 JavaScript 的严格子集 [1])。
警告
从不受信任的来源解析 JSON 数据时要小心。恶意 JSON 字符串可能会导致解码器消耗大量的 CPU 和内存资源。建议限制要解析的数据的大小。
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 super().default(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 序列化器。
注意
默认情况下,此模块的编码器和解码器会保留输入和输出顺序。只有在底层容器无序的情况下才会丢失顺序。
基本用法¶
- 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()
的类文件对象)。如果 skipkeys 为 true(默认值:
False
),则非基本类型(str
、int
、float
、bool
、None
)的字典键将被跳过,而不是引发TypeError
。json
模块始终生成str
对象,而不是bytes
对象。因此,fp.write()
必须支持str
输入。如果 ensure_ascii 为 true(默认值),则保证输出中的所有传入非 ASCII 字符都将被转义。如果 ensure_ascii 为 false,则这些字符将按原样输出。
如果 check_circular 为 false(默认值:
True
),则将跳过对容器类型的循环引用检查,并且循环引用将导致RecursionError
(或更糟)。如果 allow_nan 为 false(默认值:
True
),则序列化超出范围的float
值(nan
、inf
、-inf
)将导致ValueError
,以严格遵守 JSON 规范。如果 allow_nan 为 true,则将使用它们的 JavaScript 等效项(NaN
、Infinity
、-Infinity
)。如果 indent 是一个非负整数或字符串,则 JSON 数组元素和对象成员将使用该缩进级别进行美化打印。缩进级别为 0、负数或
""
将只插入换行符。None
(默认值)选择最紧凑的表示形式。使用正整数缩进将在每个级别缩进那么多空格。如果 indent 是一个字符串(例如"\t"
),则该字符串将用于缩进每个级别。在 3.2 版更改: 除了整数之外,还允许使用字符串作为 indent。
如果指定了 separators,则它应该是一个
(item_separator, key_separator)
元组。如果 indent 为None
,则默认为(', ', ': ')
,否则为(',', ': ')
。要获得最紧凑的 JSON 表示形式,应指定(',', ':')
以消除空格。版本 3.4 中的变化: 如果 indent 不为
None
,则使用(',', ': ')
作为默认值。如果指定了 default,则它应该是一个函数,当遇到无法序列化的对象时将调用该函数。它应该返回该对象的 JSON 可编码版本或引发
TypeError
。如果未指定,则会引发TypeError
。如果 sort_keys 为 true(默认值:
False
),则字典的输出将按键排序。要使用自定义的
JSONEncoder
子类(例如,覆盖default()
方法以序列化其他类型),请使用 cls 关键字参数指定它;否则将使用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
使用。此功能可用于实现自定义解码器。如果同时定义了 object_hook,则 object_pairs_hook 优先。版本 3.1 中的变化: 添加了对 object_pairs_hook 的支持。
如果指定了 parse_float,则将使用每个要解码的 JSON 浮点数的字符串调用它。默认情况下,这等效于
float(num_str)
。这可以用于对 JSON 浮点数使用其他数据类型或解析器(例如decimal.Decimal
)。如果指定了 parse_int,则将使用每个要解码的 JSON 整数的字符串调用它。默认情况下,这等效于
int(num_str)
。这可以用于对 JSON 整数使用其他数据类型或解析器(例如float
)。3.11 版更改: 现在,
int()
的默认 parse_int 会通过解释器的 整数字符串转换长度限制 来限制整数字符串的最大长度,以帮助避免拒绝服务攻击。如果指定了 parse_constant,它将使用以下字符串之一调用:
'-Infinity'
、'Infinity'
、'NaN'
。如果遇到无效的 JSON 数字,可以使用它来引发异常。3.1 版更改: parse_constant 不再对 'null'、'true'、'false' 进行调用。
要使用自定义
JSONDecoder
子类,请使用cls
关键字参数指定它;否则将使用JSONDecoder
。额外的关键字参数将传递给类的构造函数。如果要反序列化的数据不是有效的 JSON 文档,则会引发
JSONDecodeError
。版本 3.6 中的变化: 所有可选参数现在都是仅关键字参数。
3.6 版更改: fp 现在可以是 二进制文件。输入编码应为 UTF-8、UTF-16 或 UTF-32。
编码器和解码器¶
- 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 对象的结果调用,并带有一个有序的键值对列表。将使用 object_pairs_hook 的返回值而不是
dict
。此功能可用于实现自定义解码器。如果还定义了 object_hook,则 object_pairs_hook 优先。版本 3.1 中的变化: 添加了对 object_pairs_hook 的支持。
如果指定了 parse_float,则将使用每个要解码的 JSON 浮点数的字符串调用它。默认情况下,这等效于
float(num_str)
。这可以用于对 JSON 浮点数使用其他数据类型或解析器(例如decimal.Decimal
)。如果指定了 parse_int,则将使用每个要解码的 JSON 整数的字符串调用它。默认情况下,这等效于
int(num_str)
。这可以用于对 JSON 整数使用其他数据类型或解析器(例如float
)。如果指定了 parse_constant,它将使用以下字符串之一调用:
'-Infinity'
、'Infinity'
、'NaN'
。如果遇到无效的 JSON 数字,可以使用它来引发异常。如果 strict 为假(默认为
True
),则字符串中将允许使用控制字符。此上下文中的控制字符是指字符代码在 0-31 范围内的字符,包括'\t'
(制表符)、'\n'
、'\r'
和'\0'
。如果要反序列化的数据不是有效的 JSON 文档,则会引发
JSONDecodeError
。3.6 版更改: 所有参数现在都是 仅限关键字参数。
- decode(s)¶
返回 s(包含 JSON 文档的
str
实例)的 Python 表示形式。如果给定的 JSON 文档无效,则会引发
JSONDecodeError
。
- 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
字典
对象
列表,元组
数组
字符串
字符串
整数,浮点数,整数和浮点数派生的枚举
数字
真
真
假
假
无
空
版本 3.4 中的变化: 添加了对整数和浮点数派生的枚举类的支持。
要扩展此功能以识别其他对象,请创建子类并使用另一个方法实现
default()
方法,如果可能,该方法将为o
返回可序列化对象,否则它应该调用超类实现(以引发TypeError
)。如果 skipkeys 为 false(默认值),则在尝试编码不是
str
、int
、float
或None
的键时,将引发TypeError
。如果 skipkeys 为 true,则此类项目将被简单跳过。如果 ensure_ascii 为 true(默认值),则保证输出中的所有传入非 ASCII 字符都将被转义。如果 ensure_ascii 为 false,则这些字符将按原样输出。
如果 check_circular 为 true(默认值),则在编码期间将检查列表、字典和自定义编码对象是否存在循环引用,以防止无限递归(这将导致
RecursionError
)。否则,将不进行此类检查。如果 allow_nan 为 true(默认值),则
NaN
、Infinity
和-Infinity
将按原样编码。此行为不符合 JSON 规范,但与大多数基于 JavaScript 的编码器和解码器一致。否则,编码此类浮点数将是ValueError
。如果 sort_keys 为 true(默认值:
False
),则字典的输出将按键排序;这对于回归测试很有用,可以确保每天都能比较 JSON 序列化。如果 indent 是一个非负整数或字符串,则 JSON 数组元素和对象成员将使用该缩进级别进行美化打印。缩进级别为 0、负数或
""
将只插入换行符。None
(默认值)选择最紧凑的表示形式。使用正整数缩进将在每个级别缩进那么多空格。如果 indent 是一个字符串(例如"\t"
),则该字符串将用于缩进每个级别。在 3.2 版更改: 除了整数之外,还允许使用字符串作为 indent。
如果指定了 separators,则它应该是一个
(item_separator, key_separator)
元组。如果 indent 为None
,则默认为(', ', ': ')
,否则为(',', ': ')
。要获得最紧凑的 JSON 表示形式,应指定(',', ':')
以消除空格。版本 3.4 中的变化: 如果 indent 不为
None
,则使用(',', ': ')
作为默认值。如果指定了 default,则它应该是一个函数,当遇到无法序列化的对象时将调用该函数。它应该返回该对象的 JSON 可编码版本或引发
TypeError
。如果未指定,则会引发TypeError
。3.6 版更改: 所有参数现在都是 仅限关键字参数。
- default(o)¶
在子类中实现此方法,以便它为 o 返回可序列化对象,或者调用基实现(以引发
TypeError
)。例如,要支持任意迭代器,您可以像这样实现
default()
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 super().default(o)
- encode(o)¶
返回 Python 数据结构 o 的 JSON 字符串表示形式。例如
>>> json.JSONEncoder().encode({"foo": ["bar", "baz"]}) '{"foo": ["bar", "baz"]}'
- iterencode(o)¶
对给定对象 o 进行编码,并在可用时生成每个字符串表示形式。例如
for chunk in json.JSONEncoder().iterencode(bigobject): mysocket.write(chunk)
异常¶
标准合规性和互操作性¶
JSON 格式由 RFC 7159 和 ECMA-404 指定。本节详细介绍了此模块与 RFC 的合规性级别。为简单起见,JSONEncoder
和 JSONDecoder
子类以及未明确提及的参数不予考虑。
此模块不严格遵守 RFC,它实现了一些对 JavaScript 有效但对 JSON 无效的扩展。特别是
接受并输出无限和 NaN 数值;
接受对象中的重复名称,并且仅使用最后一个名称-值对的值。
由于 RFC 允许符合 RFC 的解析器接受不符合 RFC 的输入文本,因此在默认设置下,此模块的反序列化器在技术上符合 RFC。
字符编码¶
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
中时)此类序列的代码点。
无限和 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 参数来更改此行为。
对象中重复的名称¶
RFC 指定 JSON 对象中的名称应该是唯一的,但没有强制规定如何处理 JSON 对象中的重复名称。 默认情况下,此模块不会引发异常; 相反,它会忽略给定名称的最后一个名称-值对以外的所有名称-值对。
>>> weird_json = '{"x": 1, "x": 2, "x": 3}'
>>> json.loads(weird_json)
{'x': 3}
可以使用 object_pairs_hook 参数来更改此行为。
顶级非对象、非数组值¶
由已过时的 RFC 4627 指定的旧版 JSON 要求 JSON 文本的顶级值必须是 JSON 对象或数组(Python dict
或 list
),而不能是 JSON 空值、布尔值、数字或字符串值。 RFC 7159 刪除了该限制,并且此模块在其序列化器或反序列化器中从未实现过该限制。
无论如何,为了获得最大的互操作性,您可能希望自愿遵守此限制。
实现限制¶
某些 JSON 反序列化器实现可能会对以下内容设置限制:
可接受的 JSON 文本的大小
JSON 对象和数组的最大嵌套级别
JSON 数字的范围和精度
JSON 字符串的内容和最大长度
除了相关 Python 数据类型本身或 Python 解释器本身的限制之外,此模块没有施加任何此类限制。
序列化为 JSON 时,请注意可能使用您的 JSON 的应用程序中的任何此类限制。 特别是,JSON 数字通常会被反序列化为 IEEE 754 双精度数字,因此会受到该表示形式的范围和精度限制。 当序列化极大数量级的 Python int
值或序列化“奇异”数字类型的实例(例如 decimal.Decimal
)时,这一点尤其重要。
命令行界面¶
源代码: 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
选项按键的字母顺序对字典的输出进行排序。
命令行选项¶
- 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 版新增。
- --no-ensure-ascii¶
禁用对非 ASCII 字符的转义,有关详细信息,请参阅
json.dumps()
。3.9 版新增。
- --json-lines¶
将每行输入解析为单独的 JSON 对象。
3.8 版新增。
- --indent, --tab, --no-indent, --compact¶
用于空格控制的互斥选项。
3.9 版新增。
- -h, --help¶
显示帮助消息。
脚注