# `json` --- JSON 編碼器與解碼器

原始碼：Lib/json/__init__.py

JSON (JavaScript Object Notation) 是一個輕量化的資料交換格式，在 RFC 7159（其廢棄了 RFC 4627）及 ECMA-404 裡面有詳細說明，它啟發自 JavaScript 的物件字面語法 (object literal syntax)（雖然它並不是 JavaScript 的嚴格子集 [1]）。

警告

當剖析無法信任來源的 JSON 資料時要小心。一段惡意的 JSON 字串可能會導致解碼器耗費大量 CPU 與記憶體資源。建議限制剖析資料的大小。

`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 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', ']']

从命令行使用 `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 的一个子集。 由该模块的默认设置所产生的 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)

  使用这个 转换表 将 obj 序列化为 JSON 格式化流形式的 fp (支持 `.write()` 的 file-like object)。

  如果 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`），則針對不同容器型別的循環參照 (circular reference) 的檢查將會被跳過，若有循環參照則最後將引發 `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 版的變更: 所有可選參數現在都是僅限關鍵字了。

  備註

  與 `pickle` 和 `marshal` 不同，JSON 不是框架協定，因此嘗試使用相同的 fp 重複呼叫 `dump()` 來序列化多個物件將導致無效的 JSON 檔案。

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 現在對於整數字串有長度上限，上限是直譯器的整數字串轉換長度限制，這能防止阻斷服務攻擊 (denial of service attacks)。

  如果 parse_constant 有值，那麼以 `'-Infinity'`、`'Infinity'` 或 `'NaN'` 字串其中之一來呼叫。這也可用於在遇到無效的 JSON 數字時引發一個例外。

  在 3.1 版的變更: parse_constant 不再以 'null'、 'true'、 'false' 呼叫了。

  要使用自定义的 `JSONDecoder` 子类，用 `cls` 指定他；否则使用 `JSONDecoder` 。额外的关键词参数会通过类的构造函数传递。

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

  在 3.6 版的變更: 所有可選參數現在都是僅限關鍵字了。

  在 3.6 版的變更: fp 现在可以是 binary file 。输入编码应当是 UTF-8 ， UTF-16 或者 UTF-32 。

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

  使用这个 转换表 将 s (一个包含 JSON 文档的 `str`, `bytes` 或 `bytearray` 实例) 反序列化为 Python 对象。

  其他参数的含义与 `load()` 中的相同。

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

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

  简单的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 的 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 | object
  list, tuple | array
  str | string
  int, float, int 和 float 派生的枚举 | number
  True | true
  False | false
  None | null

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

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

  如果 skipkeys 为假值（默认），则当尝试对非 `str`, `int`, `float` 或 `None` 的键进行编码时将会引发 `TypeError`。 如果 skipkeys 为真值，这些条目将被直接跳过。

  如果 ensure_ascii 是 true （即默认值），输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 是 false，这些字符会原样输出。

  如果 check_circular 为真值（默认），那么列表、字典和自定义的已编码对象将在编码期间进行循环引用检查以防止无限递归 (无限递归会导致 `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)

## 例外

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.

  Added in version 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 strings` 间的转换定义的，并且因此不能直接解决字符编码的问题。

RFC 禁止添加字符顺序标记（ BOM ）在 JSON 文本的开头，这个模块的序列化器不添加 BOM 标记在它的输出上。 RFC，准许 JSON 反序列化器忽略它们输入中的初始 BOM 标记，但不要求。此模块的反序列化器引发 `ValueError` 当存在初始 BOM 标记。

RFC 不会明确禁止包含字节序列的 JSON 字符串这不对应有效的 Unicode 字符（比如 不成对的 UTF-16 的替代物），但是它确实指出它们可能会导致互操作性问题。默认下，模块对这样的序列接受和输出（当在原始 `str` 存在时）代码点。

### Infinite 和 NaN 数值

RFC 不允许 infinite 或者 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_parts_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` 值时，或者当序列化 "exotic" 数值类型的实例时比如 `decimal.Decimal` 。

## 命令列介面

原始碼：Lib/json/tool.py

The `json.tool` module provides a simple command line interface to validate and pretty-print JSON objects.

如果未指定可选的 `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

  将字典输出按照键的字母顺序排序。

  Added in version 3.5.

--no-ensure-ascii

  禁用非 ASCII 字符的转义，详情参见 `json.dumps()`。

  Added in version 3.9.

--json-lines

  将每个输入行解析为单独的 JSON 对象。

  Added in version 3.8.

--indent, --tab, --no-indent, --compact

  用于空白符控制的互斥选项。

  Added in version 3.9.

-h, --help

  显示帮助消息。

註解

[1]

正如 RFC 7159 的勘误表 所说明的，JSON 允许以字符串表示字面值字符 U+2028 (LINE SEPARATOR) 和 U+2029 (PARAGRAPH SEPARATOR)，而 JavaScript (在 ECMAScript 5.1 版中) 不允许。