json
— JSON 编码器和解码器¶
源代码: Lib/json/__init__.py
JSON (JavaScript 对象表示法),由 RFC 7159 (它取代了 RFC 4627) 和 ECMA-404 指定,是一种受 JavaScript 对象字面量语法启发的轻量级数据交换格式(尽管它不是 JavaScript 的严格子集 [1] )。
警告
解析来自不受信任来源的 JSON 数据时要小心。恶意的 JSON 字符串可能会导致解码器消耗大量的 CPU 和内存资源。建议限制要解析的数据的大小。
json
公开了一个 API,该 API 对于标准库 marshal
和 pickle
模块的用户来说是熟悉的。
编码基本 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({'6': 7, '4': 5}, sort_keys=True, indent=4))
{
"4": 5,
"6": 7
}
专门化 JSON 对象编码
>>> import json
>>> def custom_json(obj):
... if isinstance(obj, complex):
... return {'__complex__': True, 'real': obj.real, 'imag': obj.imag}
... raise TypeError(f'Cannot serialize object of {type(obj)}')
...
>>> json.dumps(1 + 2j, default=custom_json)
'{"__complex__": true, "real": 1.0, "imag": 2.0}'
解码 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
),则严格遵守 JSON 规范,序列化超出范围的float
值(nan
、inf
、-inf
)将会是ValueError
。 如果 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 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
使用。此功能可用于实现自定义解码器。如果还定义了 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
kwarg 指定;否则将使用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
object
dict
array
list
string
str
number (int)
int
number (real)
float
true
True
false
False
null
None
它还将
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 为 false (默认值为
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
dict
object
list,tuple
array
str
string
int, float,int 和 float 派生的枚举
number
True
true
False
false
None
null
3.4 版本更改: 添加了对 int 和 float 派生的 Enum 类的支持。
要将其扩展以识别其他对象,请继承并实现一个
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 要求 JSON 使用 UTF-8、UTF-16 或 UTF-32 表示,其中 UTF-8 是建议的默认值,以实现最大互操作性。
按照 RFC 允许但不强制的要求,此模块的序列化器默认设置 ensure_ascii=True,从而转义输出,使生成的字符串仅包含 ASCII 字符。
除了 ensure_ascii 参数外,此模块严格定义为 Python 对象和 Unicode 字符串
之间的转换,因此不直接处理字符编码问题。
RFC 禁止在 JSON 文本的开头添加字节顺序标记 (BOM),此模块的序列化器不会在其输出中添加 BOM。RFC 允许但不要求 JSON 反序列化器忽略其输入中的初始 BOM。当存在初始 BOM 时,此模块的反序列化器会引发 ValueError
。
RFC 没有明确禁止包含不对应于有效 Unicode 字符的字节序列(例如,未配对的 UTF-16 代理项)的 JSON 字符串,但它确实指出它们可能会导致互操作性问题。默认情况下,此模块接受并输出(当存在于原始 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 null、布尔值、数字或字符串值。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¶
显示帮助信息。
脚注