# `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` 來驗證 JSON 語法和美化呈現方式：

    $ 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 分隔符設定的話），這個模組的輸出也符合 YAML 1.0 和 1.1 的子集合規範。因此你也可以利用這個模組來當作 YAML 的序列化工具（serializer）。

備註

這個模組的編、解碼器預設會保存輸入與輸出資料的順序關係，除非一開始的輸入本身就是無序的。

## 基本用法

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)

  Serialize obj as a JSON formatted stream to fp (a `.write()`-supporting file-like object) using this Python-to-JSON conversion table.

  備註

  與 `pickle` 和 `marshal` 不同，JSON 不具有二進位分框（binary framed）的協定，因此嘗試重複呼叫 `dump()` 來序列化多個物件到同一個 fp 裡將導致無效的 JSON 檔案。

  參數:

    - obj (object) -- The Python object to be serialized.

    - fp (file-like object) -- The file-like object obj will be serialized to. The `json` module always produces `str` objects, not `bytes` objects, therefore `fp.write()` must support `str` input.

    - skipkeys (bool) -- If `True`, keys that are not of a basic type (`str`, `int`, `float`, `bool`, `None`) will be skipped instead of raising a `TypeError`. Default `False`.

    - ensure_ascii (bool) -- If `True` (the default), the output is guaranteed to have all incoming non-ASCII characters escaped. If `False`, these characters will be outputted as-is.

    - check_circular (bool) -- If `False`, the circular reference check for container types is skipped and a circular reference will result in a `RecursionError` (or worse). Default `True`.

    - allow_nan (bool) -- If `False`, serialization of out-of-range `float` values (`nan`, `inf`, `-inf`) will result in a `ValueError`, in strict compliance with the JSON specification. If `True` (the default), their JavaScript equivalents (`NaN`, `Infinity`, `-Infinity`) are used.

    - cls (a `JSONEncoder` subclass) -- If set, a custom JSON encoder with the `default()` method overridden, for serializing into custom datatypes. If `None` (the default), `JSONEncoder` is used.

    - indent (int | str | None) -- If a positive integer or string, JSON array elements and object members will be pretty-printed with that indent level. A positive integer indents that many spaces per level; a string (such as `"\t"`) is used to indent each level. If zero, negative, or `""` (the empty string), only newlines are inserted. If `None` (the default), the most compact representation is used.

    - separators (tuple | None) -- A two-tuple: `(item_separator, key_separator)`. If `None` (the default), separators defaults to `(', ', ': ')` if indent is `None`, and `(',', ': ')` otherwise. For the most compact JSON, specify `(',', ':')` to eliminate whitespace.

    - default (callable | None) -- A function that is called for objects that can't otherwise be serialized. It should return a JSON encodable version of the object or raise a `TypeError`. If `None` (the default), `TypeError` is raised.

    - sort_keys (bool) -- If `True`, dictionaries will be outputted sorted by key. Default `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)

  Deserialize fp to a Python object using the JSON-to-Python conversion table.

  參數:

    - fp (file-like object) -- A `.read()`-supporting text file or binary file containing the JSON document to be deserialized.

    - cls (a `JSONDecoder` subclass) -- If set, a custom JSON decoder. Additional keyword arguments to `load()` will be passed to the constructor of cls. If `None` (the default), `JSONDecoder` is used.

    - object_hook (callable | None) -- If set, a function that is called with the result of any object literal decoded (a `dict`). The return value of this function will be used instead of the `dict`. This feature can be used to implement custom decoders, for example JSON-RPC class hinting. Default `None`.

    - object_pairs_hook (callable | None) -- If set, a function that is called with the result of any object literal decoded with an ordered list of pairs. The return value of this function will be used instead of the `dict`. This feature can be used to implement custom decoders. If object_hook is also set, object_pairs_hook takes priority. Default `None`.

    - parse_float (callable | None) -- If set, a function that is called with the string of every JSON float to be decoded. If `None` (the default), it is equivalent to `float(num_str)`. This can be used to parse JSON floats into custom datatypes, for example `decimal.Decimal`.

    - parse_int (callable | None) -- If set, a function that is called with the string of every JSON int to be decoded. If `None` (the default), it is equivalent to `int(num_str)`. This can be used to parse JSON integers into custom datatypes, for example `float`.

    - parse_constant (callable | None) -- If set, a function that is called with one of the following strings: `'-Infinity'`, `'Infinity'`, or `'NaN'`. This can be used to raise an exception if invalid JSON numbers are encountered. Default `None`.

  引發:

    - JSONDecodeError -- When the data being deserialized is not a valid JSON document.

    - UnicodeDecodeError -- When the data being deserialized does not contain UTF-8, UTF-16 or UTF-32 encoded data.

  在 3.1 版的變更:

  - Added the optional object_pairs_hook parameter.

  - 遭遇 'null'、'true' 或 'false' 時不再以 parse_constant 給定的函式來處理了。

  在 3.6 版的變更:

  - 所有可選參數現在都是僅限關鍵字參數了。

  - 現在，fp 可以是一個二進位檔案，前提是其編碼格式為 UTF-8、UTF-16 或 UTF-32。

  在 3.11 版的變更: 預設 parse_int 使用的 `int()` 函式現在有限制整數字串的長度上限了，限制由直譯器的整數字串轉換長度限制機制來達成，這能防止阻斷服務攻擊 (Denial of Service attacks)。

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

  Identical to `load()`, but instead of a file-like object, deserialize s (a `str`, `bytes` or `bytearray` instance containing a JSON document) to a Python object using this conversion table.

  在 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
  number (實數) | float
  true | True
  false | False
  null | None

  雖然 `NaN`、`Infinity` 和 `-Infinity` 並不符合 JSON 規範，但解碼器依然能正確地將其轉換到相應的 Python `float` 值。

  object_hook 是一個可選函式，其接受一個解碼後的 JSON 物件作為輸入，並使用其回傳值來取代原先的 `dict`。這個功能可用於提供自訂的去序列化（例如支援 JSON-RPC 類別提示）。

  object_pairs_hook is an optional function that will be called with the result of every JSON object decoded with an ordered list of pairs. The return value of object_pairs_hook will be used instead of the `dict`. This feature can be used to implement custom decoders. If object_hook is also defined, the object_pairs_hook takes priority.

  在 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`），那麼字串中將允許控制字元。此語境中的控制字元指的是 ASCII 字元編碼在 0～31 範圍內的字元，包括 `'\t'``（tab）、`'n'`、`'r'`` 和 `'\0'`。

  如果被去序列化（deserialized）的資料不符合 JSON 格式，將會引發 `JSONDecodeError` 例外。

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

  decode(s)

    回傳用 Python 型式表達的 s （一個含有 JSON 文件的 `str` 實例）。

    若給定的輸入不符合 JSON 格式會引發 `JSONDecodeError` 例外。

  raw_decode(s)

    將 s （一個開頭部分含有合格 JSON 文件的 `str`） 解碼，並將 JSON 文件結束點的索引值（index）和解碼結果合併為一個二元組（2-tuple）後回傳。

    這個方法可以用來解碼尾段可能帶有 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- or float-derived Enums） | number
  True | true
  False | false
  None | null

  在 3.4 版的變更: 增加對整數（int）、浮點數（float）或可作為整數或浮點數運算的衍生列舉（int- or float-derived Enums）類別的支援性。

  若要擴充此功能來識別其他物件，請繼承並實作一個 `default()` 方法。此方法應回傳一個可序列化的 `o` 物件，否則此方法應呼叫父類別的 JSONEncoder.default 方法（以引發 `TypeError` 例外）。

  If skipkeys is false (the default), a `TypeError` will be raised when trying to encode keys that are not `str`, `int`, `float`, `bool` or `None`. If skipkeys is true, such items are simply skipped.

  如果 ensure_ascii 被設為 true（預設值），則輸出時將確保所有輸入的非 ASCII 字元都會被轉義。若 ensure_ascii 為 false，則這些字元將照原樣輸出。

  如果 check_circular 為 true（預設值），則會在編碼期間檢查串列（list）、字典（dict）和自訂編碼物件的循環參照，以防止無限遞迴（一個會導致 `RecursionError` 例外的問題）。否則不會進行此類檢查。

  如果 allow_nan 為 true（預設值），則 `NaN`、`Infinity` 和 `-Infinity` 將按照原樣進行編碼。請記得此行為不符合標準 JSON 規範，但的確與大多數基於 JavaScript 的編碼器和解碼器一致。否則若設為 false，嘗試對這些浮點數進行編碼將引發 `ValueError` 例外。

  如果 sort_keys 為 true（預設值：`False`），則 dictionary（字典）的輸出將按鍵值排序。這項功能可確保 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` 例外。

    舉例來說，想要讓編碼器支援任意疊代器（iterator），你可以實作這樣子的 `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 編碼，並將結果統整為一個能依序產生（yield）各結果字串的物件。如下例：

        for chunk in json.JSONEncoder().iterencode(bigobject):
            mysocket.write(chunk)

## 例外

exception json.JSONDecodeError(msg, doc, pos)

  `ValueError` 的子類別具有下列額外屬性：

  msg

    未受格式化的錯誤訊息。

  doc

    正在被剖析的 JSON 文件。

  pos

    doc 剖析失敗處的起始點的索引值。

  lineno

    pos 所在的列（line）數。

  colno

    pos 所在的行（column）數。

  在 3.5 版被加入.

## 合規性與互通性（Interoperability）

JSON 格式是由 RFC 7159 和 ECMA-404 規範的。本節詳細說明了本模組對 RFC 的遵循程度。簡單起見，`JSONEncoder` 和 `JSONDecoder` 子類別以及未明確提及的參數將不予討論。

這個模組的部份實作並未非常嚴格地遵循 RFC 規範。準確來說，下列實際實作符合 JavaScript 語法格式，但並不符合 JSON 格式：

- 無限（Infinite）和非數字（NaN）值會被接受。

- 同一個物件內可以有重複的名稱，但只有最後一個同名物件是有效的。

不過 RFC 准許遵循 RFC 的剖析器接受不合規的文字輸入，所以技術上來說若以預設設定運作，本模組的去序列化器（deserializer）是符合 RFC 規範的。

### 字元編碼格式

RFC 要求 JSON 必須以 UTF-8、UTF-16 或 UTF-32 格式編碼。並推薦以 UTF-8 編碼以達成最佳的互通性。

RFC 准許但並不強制編碼器的 ensure_ascii=True 行為是預設值，但本模組依然實作了此一選項作為預設，因此本模組預設會轉義所有非 ASCII 字元。

除了 ensure_ascii 選項參數之外，本模組嚴格遵循 Python 物件與 `Unicode strings` 之間的轉換規範，因此並不另外處理字元編碼的問題。

RFC 禁止在文件的開頭加上端序記號（Byte Order Mark），因此本模組的序列化器（serializer）也不會在輸出中加入端序記號。RFC 允許但不強制 JSON 去序列化器（deserializer）忽略文件初始的端序記號，因此本模組的去序列化器將在遭遇位於文件開頭的端序記號時引發 `ValueError` 例外。

RFC 並未明確禁止 JSON 文件包含無法對應有效 Unicode 字元的位元組序列（例如未配對的 UTF-16 代理對（surrogate pairs）），但這個特性的確可能會引起相容性問題。預設情況下，當原始輸入的 `str` 中存在此類序列時，該模組將接受並輸出這些序列的編碼位置（code points）。

### 正負無限與非數值

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 參數可以改變這個行為。

### 物件內重複的名稱

RFC 規範僅表明 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、boolean、數字或字串值。 RFC 7159 移除了這個限制，而本模組的序列化器或去串列化器中未曾實施過該限制。

如果想要最大限度地保留互通性，你可能還是會想要自行施加這個限制。

### 實作限制

某些 JSON 去序列化器的實作可能會造成下列限制：

- JSON 文件長度上限

- JSON 物件或陣列的最大巢狀層數（level of nesting）限制

- 數字的精準度或範圍

- JSON 字串長度上限

本模組除了 Python 資料型態本身或 Python 直譯器本身的限制以外，不會設定任何此類限制。

將資料序列化為 JSON 時，要注意可能會使用該 JSON 輸出的應用程式中的相關限制。特別要注意的是，JSON 數字常會被去序列化為 IEEE 754 雙精度浮點數（double），並因而受到其表示範圍和精度限制的影響。這在序列化極大的 Python `int` 數值、或是序列化特殊數字型別的實例時（例如 `decimal.Decimal`）尤其重要。

## 命令列介面

原始碼：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` 引數以按照鍵值的字母順序對輸出進行排序。

### 命令列選項

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 版被加入.

--no-ensure-ascii

  關閉非 ASCII 字元的自動轉義功能。詳情請參照 `json.dumps()`。

  在 3.9 版被加入.

--json-lines

  將每一行輸入都單獨輸出為一個 JSON 物件。

  在 3.8 版被加入.

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

  互斥的空白字元控制選項。

  在 3.9 版被加入.

-h, --help

  顯示說明訊息。

註解

[1]

如 RFC 7159 更正 所述，JSON 允許字串中出現 U+2028（列分隔符）和 U+2029（段落分隔符）字元，而 JavaScript（截至 ECMAScript 5.1 版）則不允許。