Skip to main content

19.2. json — JSON编码器和解码器

源代码: Lib/json/__init__.py


RFC 7159 (它拒绝 RFC 4627)和 ECMA-404 指定的 JSON(JavaScript对象表示法) 是一种轻量级数据交换格式,受 JavaScript 对象字面语法的启发(尽管它不是JavaScript [1] 的严格子集)。

json 公开了标准库 marshalpickle 模块的用户熟悉的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', ']']

使用 json.tool 从shell来验证和美观打印:

$ 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()file-like object)。

如果 skipkeys 为真(默认值:False),则将跳过不是基本类型(strintfloatboolNone)的dict键,而不是提高 TypeError

json 模块总是产生 str 对象,而不是 bytes 对象。因此,fp.write() 必须支持 str 输入。

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

如果 check_circular 为false(默认值:True),则将跳过容器类型的循环引用检查,循环引用将导致 OverflowError (或更差)。

如果 allow_nan 为false(默认值:True),那么它将是一个 ValueError,以严格遵守JSON规范来串行化超出范围的 float 值(naninf-inf)。如果 allow_nan 为true,将使用其等效的JavaScript(NaNInfinity-Infinity)。

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

在 3.2 版更改: 允许除了整数之外的 indent 字符串。

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

注解

picklemarshal 不同,JSON不是框架协议,因此尝试使用相同 fp 重复调用 dump() 来序列化多个对象将导致无效的JSON文件。

注解

JSON的键/值对中的键始终为 str 类型。当字典转换为JSON时,字典的所有键都会强制转换为字符串。因此,如果字典转换为JSON然后返回到字典,字典可能不等于原始字典。也就是说,loads(dumps(x)) != 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()file-like object 包含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浮点(例如 decimal.Decimal)使用另一种数据类型或解析器。

如果指定了 parse_int,将使用要解码的每个JSON int的字符串进行调用。默认情况下,这相当于 int(num_str)。这可以用于为JSON整数(例如 float)使用另一种数据类型或解析器。

如果指定,parse_constant 将使用以下字符串之一调用:'-Infinity''Infinity''NaN'。这可以用于在遇到无效的JSON数字时引发异常。

在 3.1 版更改: parse_constant 不再被调用’null’,’true’,’false’。

要使用自定义 JSONDecoder 子类,请使用 cls kwarg指定它;否则使用 JSONDecoder。额外的关键字参数将被传递给类的构造函数。

如果反序列化的数据不是有效的JSON文档,则会引发 JSONDecodeError

在 3.6 版更改: 所有可选参数现在是 仅限关键字

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文档的 strbytesbytearray 实例)反序列化为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

object

dict

array

list

string

str

number (int)

int

number (real)

浮动

true

True

false

False

null

None

它还理解 NaNInfinity-Infinity 作为它们对应的 float 值,这在JSON规范之外。

如果指定了 object_hook,将使用每个解析的JSON对象的结果调用它,并且它的返回值将用于替换给定的 dict。这可以用于提供自定义反序列化(例如支持JSON-RPC类提示)。

object_pairs_hook,如果指定,将使用对的有序列表解码的每个JSON对象的结果进行调用。将使用 object_pairs_hook 的返回值而不是 dict。该特征可以用于实现依赖于键和值对被解码的顺序的自定义解码器(例如,collections.OrderedDict() 将记住插入的顺序)。如果还定义了 object_hook,则 object_pairs_hook 优先。

在 3.1 版更改: 添加了对 object_pairs_hook 的支持。

如果指定了 parse_float,将使用要解码的每个JSON浮点的字符串进行调用。默认情况下,这相当于 float(num_str)。这可以用于为JSON浮点(例如 decimal.Decimal)使用另一种数据类型或解析器。

如果指定了 parse_int,将使用要解码的每个JSON int的字符串进行调用。默认情况下,这相当于 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文档开头的 str)解码JSON文档,并返回一个2元组的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

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 为假(默认值),则它是尝试对不是 strintfloatNone 的密钥进行编码的 TypeError。如果 skipkeys 为真,则这样的项目被简单地跳过。

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

如果 check_circular 为true(默认值),则在编码期间将检查列表,dases和自定义编码对象的循环引用,以防止无限递归(这将导致 OverflowError)。否则,不进行这种检查。

如果 allow_nan 为真(默认值),则 NaNInfinity-Infinity 将被如此编码。此行为不符合JSON规范,但与大多数基于JavaScript的编码器和解码器一致。否则,它将是一个 ValueError 来编码这样的浮动。

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

如果 indent 是非负整数或字符串,那么JSON数组元素和对象成员将以该缩进级别打印。缩进级别为0,negative或 "" 只会插入换行符。 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)。

例如,要支持任意迭代器,您可以实现这样的默认值:

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数据结构(o)的JSON字符串表示形式。例如:

>>> 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, end=None)

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

msg

未格式化的错误消息。

doc

解析的JSON文档。

pos

解析失败的 doc 的开始索引。

lineno

该行对应于 pos

colno

该列对应于 pos

3.5 新版功能.

19.2.4. 标准合规性和互操作性

JSON格式由 RFC 7159ECMA-404 指定。本节详细说明此模块符合RFC的级别。为了简单起见,不考虑 JSONEncoderJSONDecoder 亚类以及除了明确提及的参数之外的参数。

此模块以严格的方式不符合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 strings 之间的转换来定义,因此不直接解决字符编码的问题。

RFC禁止在JSON文本的开头添加字节顺序标记(BOM),并且此模块的序列化程序不会向其输出添加BOM。 RFC允许,但不要求JSON解串器在其输入中忽略初始BOM。当存在初始BOM时,该模块的解串器提升 ValueError

RFC没有明确禁止包含不对应于有效Unicode字符(例如,不成对的UTF-16代理)的字节序列的JSON字符串,但它确实注意到它们可能导致互操作性问题。默认情况下,此模块接受和输出(当存在于原始 str 中)这样的序列的代码点。

19.2.4.2. 无限和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 参数可以用于改变这种行为。

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 dictlist),并且不能是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. 命令行界面

源代码: Lib/json/tool.py


json.tool 模块提供了一个简单的命令行界面来验证和美观打印JSON对象。

如果未指定可选的 infileoutfile 参数,将分别使用 sys.stdinsys.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版)不支持。