json --- JSON 编码器和解码器

源代码: Lib/json/__init__.py


JSON (JavaScript Object Notation),由 RFC 7159 (它取代了 RFC 4627) 和 ECMA-404 进行规范,是一个受到 JavaScript 对象字面值语法启发的轻量级数据交换格式 (虽然它并不是严格意义上的 JavaScript 子集 [1] )。

备注

术语"对象"在 Python 语言 JSON 处理的上下文中存在歧义。 Python 中的所有值都是对象。 在 JSON 中,对象则是指包裹在花括号里的任何数据,这类似于 Python 字典。

警告

在解析来自不受信任来源的 JSON 数据时要小心谨慎。 恶意的 JSON 字符串可能导致解码器消耗大量 CPU 和内存资源。 建议对要解析的数据大小进行限制。

本模块提供了会让标准库 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({'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')
>>> json.loads('{"name": "point", "coords": [[1, 2], [3, 4]]}',
...     array_hook=tuple)
{'name': 'point', 'coords': ((1, 2), (3, 4))}
>>> json.loads('{"name": "point", "coords": [1, 2]}',
...     object_pairs_hook=frozendict, array_hook=tuple)
frozendict({'name': 'point', 'coords': (1, 2)})

扩展 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 来验证并美化打印:

$ echo '{"json":"obj"}' | python -m json
{
    "json": "obj"
}
$ echo '{1.2:3.4}' | python -m json
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

详细文档请参见 命令行接口。

备注

JSON 是 YAML 1.2 的一个子集。 由该模块的默认设置所产生的 JSON(尤其是默认的 separators 值)也是 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)

使用这个 Python 至 JSON 转换表 将 obj 序列化为输出到 fp (一个支持 .write() 的 file-like object) 的已格式化的 JSON 流。

备注

与 pickle 和 marshal 不同,JSON 不是一个具有框架的协议,所以尝试多次使用同一个 fp 调用 dump() 来序列化多个对象会产生一个不合规的 JSON 文件。

参数:
  • obj (object) -- 要序列化的 Python 对象。

  • fp (file-like object) -- obj 将被序列化输出到的文件型对象。 json 模块总是产生 str 对象,而不是 bytes 对象,因此 fp.write() 必须支持 str 输入。

  • skipkeys (bool) -- 如为 True,则不为基本类型 (str, int, float, bool, None) 的键将被跳过而不会引发 TypeError。 默认为 False。

  • ensure_ascii (bool) -- 如果为 True (默认值),输出将确保对所有输入的非 ASCII 和不可打印字符进行转义。 如果为 False,则所有字符将被原样输出,只有必须被转义的字符除外:引号、反斜线,以及 U+0000 至 U+001F 范围的控制字符。

  • check_circular (bool) -- 如为 False,则对容器类型的循环引用检查会被跳过并且循环引用将导致 RecursionError (或更糟的情况)。 默认为 True。

  • allow_nan (bool) -- 如为 False,则对超范围的 float 值 (nan, inf, -inf) 进行序列化将导致 ValueError,以严格遵循 JSON 规范。 如为 True (默认值),则将使用它们的 JavaScript 等价形式 (NaN, Infinity, -Infinity)。

  • cls (a JSONEncoder subclass) -- 如果设置,则使用一个重写了 default() 方法的自定义 JSON 编码器,用以序列化为自定义的数据类型。 如为 None (默认值),则使用 JSONEncoder。

  • indent (int | str | None) -- 如果是正整数或字符串,JSON 数组元素和对象成员将使用相应的缩进层级进行美化打印。 正整数代表每一层缩进相应数量的空格;字符串(例如 "\t")用于缩进每一层。 如果为零、负数或 "" (空字符串),则仅插入换行符。 如果为 None (默认值),则不插入换行符。

  • separators (tuple | None) -- 一个二元组: (item_separator, key_separator)。 如为 None (默认值),则默认当 indent 为 None 时 separators 为 (', ', ': '),否则为 (',', ': ')。 要使用最紧凑形式的 JSON,可指定 (',', ':') 来去除空格。

  • default (callable | None) -- 当对象无法被序列化时将被调用的函数。 它应该返回一个可被 JSON 编码的版本或是引发 TypeError。 如为 None (默认值),则会引发 TypeError。

  • sort_keys (bool) -- 如为 True,则字典输出将按键排序。 默认为 False。

备注

JSON 键/值对中的键始终为 str 类型。 当字典被转换为 JSON 时,字典的所有键都会被转换为字符串。 因此,如果将字典转换为 JSON 然后再转换回字典,该字典可能不等于原来的字典。 也就是说,如果 x 具有非字符串的键,则 loads(dumps(x)) != x。 sort_keys 会在键被转换为字符串之前对其进行排序,因此数值键是按数值而不是按其字符串表示形式进行排序的。

在 3.2 版本发生变更: 现允许使用字符串作为 indent 而不再仅仅是整数。

在 3.4 版本发生变更: 现当 indent 不是 None 时,采用 (',', ': ') 作为默认值。

在 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.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, array_hook=None, **kw)

使用 JSON 至 Python 转换表 将 fp 反序列化为 Python 对象。

参数:
  • fp (file-like object) -- 一个包含要执行反序列化的 JSON 文档的支持 .read() 的 text file 或 binary file。

  • cls (a JSONDecoder subclass) -- 如果设定此参数,则使用自定义的JSON解码器。任何传递给 load() 方法的多余关键字参数都会被传递给 cls 的构造器。如果传入 None (默认值),则会使用 JSONDecoder 。

  • object_hook (callable | None) -- 如果设置,将是一个在调用时传入任意被解码的 JSON 对象字面值 (即 dict) 的函数。 该函数的返回值将代替该 dict 被使用。 此特性可被用于实现自定义解码器,例如 JSON-RPC 类提示。 默认值为 None。

  • object_pairs_hook (callable | None) -- 如果设置,将是一个在调用时传入以对照值的有序列表进行解码的任意 JSON 对象字面值的函数。 该函数的返回值将代替该 dict 被使用。 此特性可被用于实现自定义解码器。 如果还设置了 object_hook,则 object_pairs_hook 的优先级更高。 默认值为 None。

  • array_hook (callable | None) -- If set, a function that is called with the result of any JSON array literal decoded as a Python list. The return value of this function will be used instead of the list. This feature can be used to implement custom decoders. Default None.

  • parse_float (callable | None) -- 如果设置,将是一个在调用时以代表每个要解码的 JSON 浮点数的字符串作为参数的函数。 如为 None (默认值),则它等价于 float(num_str)。 这可被用于将 JSON 浮点数解析为自定义数据类型,例如 decimal.Decimal。

  • parse_int (callable | None) -- 如果设置,将是一个在调用时以代表每个要解码的 JSON 整数的字符串作为参数的函数。 如为 None (默认值),则它等价于 int(num_str)。 这可被用于将 JSON 整数解析为自定义数据类型,例如 float。

  • parse_constant (callable | None) -- 如果设置,将是一个以下列字符串之一作为参数的函数: '-Infinity', 'Infinity' 或 'NaN'。 这可被用于在遇到无效的 JSON 数字时引发异常。 默认值为 None。

抛出:
  • JSONDecodeError -- 当被反序列化的数据不是合法的 JSON 文档。

  • UnicodeDecodeError -- 当被反序列化的数据不包含 UTF-8, UTF-16 或 UTF-32 编码的数据。

在 3.1 版本发生变更:

  • 增加了可选的 object_pairs_hook 形参。

  • parse_constant 不再调用 'null' , 'true' , 'false' 。

在 3.6 版本发生变更:

在 3.11 版本发生变更: 现在 int() 默认的 parse_int 会通过解释器的 整数字符串长度上限 来限制整数字符串的最大长度以帮助避免拒绝服务攻击。

在 3.15 版本发生变更: 增加可选的 array_hook 形参。

json.loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, array_hook=None, **kw)

类似于 load(),但不是针对文件型对象,而是使用这个 转换表 将 s (一个包含 JSON 的 str, bytes 或 bytearray 实例) 反序列化为 Python 对象。

在 3.6 版本发生变更: s 现在可以为 bytes 或 bytearray 类型。 输入编码应为 UTF-8, UTF-16 或 UTF-32。

在 3.9 版本发生变更: 关键字参数 encoding 已被移除。

编码器和解码器

class json.JSONDecoder(*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None, array_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 的支持。

array_hook is an optional function that will be called with the result of every JSON array decoded as a list. The return value of array_hook will be used instead of the list. This feature can be used to implement custom decoders.

在 3.15 版本发生变更: 添加了对 array_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 的 Python 表示形式(包含一个 JSON 文档的 str 实例)。

如果给定的 JSON 文档无效则将引发 JSONDecodeError。

raw_decode(s)

从 s 中解码出 JSON 文档(以 JSON 文档开头的一个 str 对象)并返回一个 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

dict, frozendict

object -- 对象

list, tuple

array

str

string

int, float, int 和 float 派生的枚举

number

True

true

False

false

None

null

在 3.4 版本发生变更: 添加了对 int 和 float 派生的枚举类的支持

在 3.15 版本发生变更: 添加了对 frozendict 的支持。

要将其扩展至识别其他对象,需要子类化并实现 default(),如果可能还要实现另一个返回 o 的可序列化对象的方法,否则它应当调用超类实现 (来引发 TypeError)。

如果 skipkeys 为假值(默认),则当尝试对不为 str, int, float, bool 或 None 的键进行编码时将会引发 TypeError。 如果 skipkeys 为真值,这样的条目将被直接跳过。

如果 ensure_ascii 为真值(默认值),输出将确保对所有输入的非 ASCII 和不可打印字符进行转义。 如果 ensure_ascii 为假值,则所有字符将被原样输出,只有必须被转义的字符除外:引号、反斜线,以及 U+0000 至 U+001F 范围的控制字符。

如果 check_circular 为真值(默认),那么列表、字典和自定义的已编码对象将在编码期间进行循环引用检查以防止无限递归 (无限递归会导致 RecursionError)。 在其他情况下,将不会进行这种检查。

如果 allow_nan 为真值(默认),那么 NaN、Infinity 和 -Infinity 将照常进行编码。此行为不符合 JSON 规范,但与大多数基于 JavaScript 的编码器和解码器一致。否则,编码这些浮点数将引发 ValueError。

如果 sort_keys 为真值 (默认为 False),那么字典的输出将按照键排序;这对回归测试很有用,以确保可以在日常基础上对 JSON 序列化结果进行比较。

如果 indent 是一个非负整数或者字符串,那么 JSON 数组元素和对象成员会被美化输出为该值指定的缩进等级。 如果缩进等级为零、负数或者 "",则只会添加换行符。 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)
   # 让基类的 default 方法引发 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)

异常

exception json.JSONDecodeError(msg, doc, pos)

拥有以下附加属性的 ValueError 的子类:

msg

未格式化的错误消息。

doc

正在解析的 JSON 文档。

pos

The start index of doc where parsing failed.

lineno

The line corresponding to pos.

colno

The column corresponding to pos.

在 3.5 版本加入.

标准符合性和互操作性

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 中时)。

Infinite 和 NaN 数值

RFC 不允许表示无穷大或 NaN 数值。尽管如此,默认情况下,此模块接受并输出 Infinity、-Infinity 和 NaN,如同它们是有效的 JSON 数字字面值:

>>> # 这些调用均不会引发异常,但结果都不是合法的 JSON
>>> json.dumps(float('-inf'))
'-Infinity'
>>> json.dumps(float('nan'))
'NaN'
>>> # 当反序列化时也一样
>>> 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}

The object_pairs_hook parameter can be used to alter this behavior.

顶级非对象,非数组值

过时的 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 值或者序列化 "exotic" 数值类型的实例 (如 decimal.Decimal) 时尤其需要注意。

命令行接口

源代码: Lib/json/tool.py


The json module can be invoked as a script via python -m json to validate and pretty-print JSON objects. The json.tool submodule implements this interface.

如果未指定可选的 infile 和 outfile 参数,则将分别使用 sys.stdin 和 sys.stdout:

$ echo '{"json": "obj"}' | python -m json
{
    "json": "obj"
}
$ echo '{1.2:3.4}' | python -m json
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

在 3.5 版本发生变更: 输出现在将与输入顺序保持一致。 请使用 --sort-keys 选项来将输出按照键的字母顺序排序。

在 3.14 版本发生变更: The json module may now be directly executed as python -m json. For backwards compatibility, invoking the CLI as python -m json.tool remains supported.

命令行选项

infile

要被验证或美化打印的 JSON 文件:

$ python -m json 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

显示帮助消息。

备注