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

源代码: Lib/json/__init__.py


JSON (JavaScript Object Notation),由 RFC 7159(废弃了 RFC 4627)和 ECMA-404 标准指定,是一种轻量级的数据交换格式。它的灵感来自于 JavaScript 对象字面量语法(尽管它不是 JavaScript 的严格子集 [1])。

备注

在 Python 中处理 JSON 的上下文中,“对象” (object) 一词可能存在歧义。在 Python 中,所有值都是对象。而在 JSON 中,对象是指任何用花括号包裹的数据,类似于 Python 的字典。

警告

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

此模块提供的 API 对于标准库 marshalpickle 模块的用户来说应该很熟悉。

编码基本的 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 进行验证和格式化打印

$ 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 的一个子集。该模块默认设置(特别是默认的 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)

使用 Python 到 JSON 的转换表obj 序列化为 JSON 格式的流,并写入 fp(一个支持 .write()类文件对象)。

备注

picklemarshal 不同,JSON 不是一个有帧协议,因此尝试使用同一个 fp 多次调用 dump() 来序列化多个对象,将会导致一个无效的 JSON 文件。

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

  • fp (类文件对象) – obj 将被序列化到这个类文件对象中。 json 模块总是生成 str 对象,而不是 bytes 对象,因此 fp.write() 必须支持 str 输入。

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

  • ensure_ascii (bool) – 如果为 True(默认值),输出保证将所有输入的非 ASCII 字符转义。如果为 False,这些字符将按原样输出。

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

  • allow_nan (bool) – 如果为 False,在严格遵守 JSON 规范的情况下,序列化超出范围的 float 值(nan, inf, -inf)将导致 ValueError。如果为 True(默认值),则会使用它们的 JavaScript 等效项(NaN, Infinity, -Infinity)。

  • cls (JSONEncoder 的子类) – 如果设置,将使用一个自定义的 JSON 编码器,其 default() 方法被重写,用于序列化为自定义数据类型。如果为 None(默认值),则使用 JSONEncoder

  • indent (int | str | None) – 如果是正整数或字符串,JSON 数组元素和对象成员将以该缩进级别进行格式化打印。正整数表示每级缩进的空格数;字符串(例如 "\t")用于缩进每一级。如果为零、负数或 ""(空字符串),则只插入换行符。如果为 None(默认值),则使用最紧凑的表示形式。

  • separators (tuple | None) – 一个二元组:(item_separator, key_separator)。如果为 None(默认值),当 indentNone 时,separators 默认为 (', ', ': '),否则默认为 (',', ': ')。要获得最紧凑的 JSON 表示,应指定 (',', ':') 以消除空格。

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

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

在 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 的键值对中的键总是 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)

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

参数:
  • fp (类文件对象) – 一个支持 .read()文本文件二进制文件,包含要反序列化的 JSON 文档。

  • cls (JSONDecoder 的子类) – 如果设置,则为自定义的 JSON 解码器。传递给 load() 的额外关键字参数将传递给 cls 的构造函数。如果为 None(默认值),则使用 JSONDecoder

  • object_hook (可调用对象 | None) – 如果设置,此函数将被调用,其参数为任何已解码的 JSON 对象字面量(一个 dict)的结果。该函数的返回值将代替 dict。此功能可用于实现自定义解码器,例如 JSON-RPC 的类提示。默认为 None

  • object_pairs_hook (可调用对象 | None) – 如果设置,此函数将被调用,其参数为任何已解码的 JSON 对象字面量的结果,该结果是一个有序的键值对列表。此函数的返回值将代替 dict。此功能可用于实现自定义解码器。如果 object_hook 也被设置,object_pairs_hook 的优先级更高。默认为 None

  • parse_float (可调用对象 | None) – 如果设置,此函数将被调用,其参数为每个待解码的 JSON 浮点数的字符串。如果为 None(默认值),则等效于 float(num_str)。这可用于将 JSON 浮点数解析为自定义数据类型,例如 decimal.Decimal

  • parse_int (可调用对象 | None) – 如果设置,此函数将被调用,其参数为每个待解码的 JSON 整数的字符串。如果为 None(默认值),则等效于 int(num_str)。这可用于将 JSON 整数解析为自定义数据类型,例如 float

  • parse_constant (可调用对象 | 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 现在通过解释器的整数到字符串转换长度限制来限制整数字符串的最大长度,以帮助避免拒绝服务攻击。

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

load() 相同,但不是从一个类文件对象中反序列化,而是从 s(一个包含 JSON 文档的 strbytesbytearray 实例)反序列化为 Python 对象,使用此转换表

在 3.6 版更改: s 现在可以是 bytesbytearray 类型。输入编码应为 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)

简单的 JSON 解码器。

默认情况下在解码时执行以下转换

JSON

Python

对象

dict

array

list

string

str

number (int)

int

number (real)

浮点数

true

True

false

False

None

它还能将 NaNInfinity-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

raw_decode(s)

s(一个以 JSON 文档开头的 str)中解码一个 JSON 文档,并返回一个包含 Python 表示形式和文档在 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

对象

list, tuple

array

str

string

int, float, int- & float-derived Enums

True

true

False

false

None

在 3.4 版更改: 增加了对 int 和 float 派生的 Enum 类的支持。

要扩展此类以识别其他对象,请继承并实现 default() 方法,该方法如果可能,应为 o 返回一个可序列化的对象,否则应调用超类的实现(以引发 TypeError)。

如果 skipkeys 为 false(默认值),当尝试编码非 strintfloatboolNone 的键时,将引发 TypeError。如果 skipkeys 为 true,这类项将被简单地跳过。

如果 ensure_ascii 为 true(默认值),输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 为 false,这些字符将按原样输出。

如果 check_circular 为 true(默认值),那么在编码过程中会对列表、字典和自定义编码对象进行循环引用检查,以防止无限递归(这会导致 RecursionError)。否则,不会进行此类检查。

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

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

如果 indent 是一个非负整数或字符串,那么 JSON 数组元素和对象成员将以该缩进级别进行格式化打印。缩进级别为 0、负数或 "" 将只插入换行符。None(默认值)选择最紧凑的表示形式。使用正整数缩进表示每级缩进的空格数。如果 indent 是一个字符串(例如 "\t"),该字符串将用于缩进每一级。

在 3.2 版更改: 除了整数,indent 也允许使用字符串。

如果指定,separators 应该是一个 (item_separator, key_separator) 元组。如果 indentNone,默认值为 (', ', ': '),否则为 (',', ': ')。要获得最紧凑的 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)

异常

exception json.JSONDecodeError(msg, doc, pos)

ValueError 的子类,具有以下附加属性

msg

未格式化的错误消息。

doc

正在解析的 JSON 文档。

pos

doc 中解析失败的起始索引。

lineno

对应于 pos 的行号。

colno

对应于 pos 的列号。

在 3.5 版本加入。

标准合规性与互操作性

JSON 格式由 RFC 7159ECMA-404 规定。本节详细说明了此模块与 RFC 的合规程度。为简单起见,不考虑 JSONEncoderJSONDecoder 的子类,以及未明确提及的参数。

此模块并未严格遵守 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-InfinityNaN,就像它们是有效的 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 的 dictlist),而不能是 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 模块可以通过 python -m json 作为脚本调用,以验证和格式化打印 JSON 对象。json.tool 子模块实现了此接口。

如果未指定可选的 infileoutfile 参数,将分别使用 sys.stdinsys.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 版更改: json 模块现在可以直接执行为 python -m json。为了向后兼容,仍然支持将 CLI 调用为 python -m json.tool

命令行选项

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.html#sys.stdout" title="sys.stdout">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

显示帮助信息。

脚注