# 19.2. `json` - JSON编码器和解码器

源代码： Lib / json / __ init __.py

JSON (JavaScript Object Notation), specified by RFC 7159 (which obsoletes RFC 4627) and by ECMA-404, is a lightweight data interchange format inspired by JavaScript object literal syntax (although it is not a strict subset of JavaScript [1] ).

`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 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验证和pretty-print：

    $ 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)

有关详细文档，请参见Command Line Interface。

注意

JSON是YAML 1.2的子集。由此模块的默认设置（特别是默认的分隔符值）生成的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序列化为fp（a `.write()` - 支持file-like object使用此conversion table。

  如果 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`），则将跳过容器类型的循环引用检查，循环引用将导致`OverflowError`

  如果allow_nan为false（默认值：`True`），则将是`ValueError`序列化超出范围`float`值（`nan`，`inf`，`-inf`），严格遵守JSON规范。如果allow_nan为true，则将使用与其等效的JavaScript代码（`NaN`，`Infinity`，`-Infinity`）。

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

  在版本3.2中更改：允许缩进的字符串以及整数。

  如果指定，分隔符应为`（item_separator， key_separator）`元组。The default is `(', ', ': ')` if indent is `None` and `(',', ': ')` otherwise. 要获得最紧凑的JSON表示，应指定`（'，'， '：'）`

  在版本3.4中更改：使用`（'，'， '： '）作为默认值，如果缩进不是`None`。`

  如果指定，默认应该是一个函数，为不能被序列化的对象调用。它应该返回对象的JSON可编码版本或引发`TypeError`。如果未指定，则会引发`TypeError`。

  如果sort_keys为真（默认值：`False`），则字典的输出将按键排序。

  要使用自定义`JSONEncoder`子类（例如覆盖`default()`方法以序列化其他类型），使用cls kwarg指定它；否则使用`JSONEncoder`。

`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)

  使用此conversion table将obj序列化为JSON格式的`str`。参数具有与`dump()`中相同的含义。

  注意

  Unlike `pickle` and `marshal`, JSON is not a framed protocol, so trying to serialize multiple objects with repeated calls to `dump()` using the same fp will result in an invalid JSON file.

  注意

  JSON的键/值对中的键始终为`str`类型。当字典转换为JSON时，字典的所有键都会强制转换为字符串。因此，如果字典转换为JSON然后回到字典，字典可能不等于原始字典。也就是说，如果x具有非字符串键，则`载入（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 (一个包含 JSON 文档并支持 `.read()`方法的 file-like object ) 反序列化为一个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`。

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

  使用此conversion table将包含JSON文档的s（a `str`实例）解压缩为Python对象。

  其他参数与`load()`中含义相同，除了编码，它被忽略和弃用。

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

## 19.2.2. Encoders and Decoders

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
  数组 | 列表
  串 | str
  number（int） | int
  数字（实数） | 浮动
  真正 | 真正
  假 | 假
  空值 | 没有

  它还将`NaN`，`Infinity`和`-Infinity`理解为它们对应的`float`值， 。

  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'`，`'null'`，`'true'`，`'false'`。这可以用于引发异常，如果遇到无效的JSON数字。

  如果strict为false（`True`是默认值），则在字符串中将允许控制字符。在此上下文中的控制字符是具有在0-31范围内的字符代码的字符，包括`'\t'`（tab），`'\n'`，`'\r'`和`'\0'`。

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

  `decode`(s)

    返回s（包含JSON文档的`str`实例）的Python表示形式。

    如果给定的JSON文档无效，则会引发`JSONDecodeError`。

  `raw_decode`(s)

    从s（以JSON文档开头的`str`）解码JSON文档，并返回一个2元组的Python表示形式和s t4 >文档结束。

    这可以用于从可能在末尾有无关数据的字符串解码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
  --- | ---
  命令 | 目的
  列表，元组 | 数组
  str | 串
  int，float，int-＆float-derived枚举 | 数
  真正 | 真正
  假 | 假
  没有 | 空值

  在版本3.4中更改：添加了对int和float派生的Enum类的支持。

  要扩展它以识别其他对象，使用另一个返回`o`可序列化对象的方法，子类化并实现`default()`方法，否则应调用超类实现（to引发`TypeError`）。

  如果skipkeys为false（默认值），则会尝试对非str，int，float或None的键进行编码的`TypeError`。如果skipkeys为true，则此类项目将被直接跳过。

  如果ensure_ascii为true（默认值），则输出将保证所有传入的非ASCII字符都转义。如果ensure_ascii为false，则这些字符将按原样输出。

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

  If allow_nan is true (the default), then `NaN`, `Infinity`, and `-Infinity` will be encoded as such. 此行为不符合JSON规范，但与大多数基于JavaScript的编码器和解码器一致。否则，将对此类浮点进行编码为`ValueError`。

  如果sort_keys为真（默认值：`False`），那么字典的输出将按键排序；这对于回归测试非常有用，以确保JSON序列化可以在每天的基础上进行比较。

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

  在版本3.2中更改：允许缩进的字符串以及整数。

  如果指定，分隔符应为`（item_separator， key_separator）`元组。The default is `(', ', ': ')` if indent is `None` and `(',', ': ')` otherwise. 要获得最紧凑的JSON表示，应指定`（'，'， '：'）`

  在版本3.4中更改：使用`（'，'， '： '）作为默认值，如果缩进不是`None`。`

  如果指定，默认应该是一个函数，为不能被序列化的对象调用。它应该返回对象的JSON可编码版本或引发`TypeError`。如果未指定，则会引发`TypeError`。

  `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. Exceptions

exception `json.``JSONDecodeError`(msg, doc, pos, end=None)

  > Subclass of `ValueError` with the following additional attributes:

  > `msg`

  >   The unformatted error message.

  > `doc`

  >   The JSON document being parsed.

  > `pos`

  >   The start index of doc where parsing failed.

  > `lineno`

  >   The line corresponding to pos.

  > `colno`

  >   The column corresponding to pos.

  版本3.5中的新功能。

## 19.2.4. Standard Compliance and Interoperability

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

此模块以严格的方式不符合RFC，实现一些有效的JavaScript但不是有效的JSON的扩展。尤其是：

- 接受和输出无限和NaN数值；
- 接受对象内的重复名称，并且仅使用最后名称/值对的值。

由于RFC允许RFC兼容的解析器接受不符合RFC的输入文本，所以该模块的解串器在默认设置下技术上符合RFC。

### 19.2.4.1. Character Encodings

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字符的字节序列的JSON字符串。不成对的UTF-16代理），但它确实注意到，它们可能导致互操作性问题。默认情况下，此模块接受和输出（当存在于原始`str`）这样的序列的代码点。

### 19.2.4.2. Infinite and NaN Number Values

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参数可用于更改此行为。

### 19.2.4.3. Repeated Names Within an Object

RFC指定JSON对象中的名称应该是唯一的，但不要求如何处理JSON对象中的重复名称。默认情况下，此模块不引发异常；相反，它忽略除了给定名称的最后一个名称/值对之外的所有值：

    >>> weird_json = '{"x": 1, "x": 2, "x": 3}'
    >>> json.loads(weird_json)
    {'x': 3}

可以使用object_pairs_hook参数更改此行为。

### 19.2.4.4. Top-level Non-Object, Non-Array Values

由过时的 RFC 4627指定的旧版本JSON要求JSON文本的顶级值必须是JSON对象或数组（Python `dict`或`list`），并且不能是JSON空值，布尔值，数字或字符串值。 RFC 7159删除了该限制，此模块不会，也从未在其序列化器或其解串器中实现此限制。

无论如何，为了实现最大的互操作性，您可能希望自愿遵守该限制。

### 19.2.4.5. Implementation Limitations

一些JSON解串器实现可能设置以下限制：

- 接受的JSON文本的大小
- JSON对象和数组的最大嵌套级别
- JSON数字的范围和精度
- JSON字符串的内容和最大长度

除了相关的Python数据类型本身或Python解释器本身之外，此模块不强加任何此类限制。

当序列化为JSON时，请注意可能会消耗您的JSON的应用程序中的任何此类限制。特别地，通常将JSON数字反序列化为IEEE 754双精度数字，并且因此服从于该表示的范围和精度限制。当序列化非常大的Python `int`值或者序列化“异常”数值类型的实例（例如`decimal.Decimal`）时，这一点尤其重要。

## 19.2.5. Command Line Interface

源代码： 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`选项按字母顺序对字典的输出进行排序。

### 19.2.5.1. Command line options

`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版） 。