json — JSON 編碼器和解碼器

原始碼: Lib/json/__init__.py


JSON (JavaScript 物件表示法),由 RFC 7159 (它取代了 RFC 4627) 和 ECMA-404 指定,是一種受 JavaScript 物件字面量語法啟發的輕量級資料交換格式(儘管它不是 JavaScript 的嚴格子集 [1] )。

警告

解析來自不受信任來源的 JSON 資料時要小心。惡意的 JSON 字串可能會導致解碼器消耗大量的 CPU 和記憶體資源。建議限制要解析的資料的大小。

json 公開了一個 API,該 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.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 的子集。此模組的預設設定(特別是預設的 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)

obj 序列化為 JSON 格式的流到 fp (一個支援 .write()類檔案物件),使用此 轉換表

如果 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), 則會跳過容器型別的迴圈引用檢查,並且迴圈引用將導致 RecursionError (或更糟)。

如果 allow_nan 為 false(預設值:True),則嚴格遵守 JSON 規範,序列化超出範圍的 float 值(naninf-inf)將會是 ValueError。 如果 allow_nan 為 true,將使用它們的 JavaScript 等效項(NaNInfinity-Infinity)。

如果 indent 是一個非負整數或字串,那麼 JSON 陣列元素和物件成員將以該縮排級別進行美觀列印。縮排級別為 0、負數或 "" 將只插入換行符。 None(預設)選擇最緊湊的表示形式。使用正整數縮排會使每個級別縮排那麼多空格。 如果 indent 是一個字串(例如 "\t"),則該字串用於縮排每個級別。

在 3.2 版本中更改: 除了整數外,還允許使用字串作為 indent

如果指定了 separators,它應該是一個 (item_separator, key_separator) 元組。 如果 indentNone,則預設為 (', ', ': '),否則為 (',', ':')。 要獲得最緊湊的 JSON 表示形式,您應該指定 (',', ':') 來消除空格。

在 3.4 版本中更改: 如果 indent 不是 None,則使用 (',', ':') 作為預設值。

如果指定了 default,它應該是一個函式,該函式為無法序列化的物件呼叫。 它應該返回物件的 JSON 可編碼版本,或者引發 TypeError。 如果未指定,則引發 TypeError

如果 sort_keys 為 true (預設值: False), 則字典的輸出將按鍵排序。

要使用自定義的 JSONEncoder 子類(例如,覆蓋 default() 方法來序列化其他型別),請使用 cls kwarg 指定;否則將使用 JSONEncoder

在 3.6 版本中更改:所有可選引數現在都是僅關鍵字引數

注意

picklemarshal 不同,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 現在透過直譯器的 整數字符串轉換長度限制來限制整數字符串的最大長度,以幫助避免拒絕服務攻擊。

parse_constant 是一個可選函式,它將使用以下字串之一呼叫: '-Infinity''Infinity''NaN'。如果遇到無效的 JSON 數字,可以使用此方法引發異常。

在 3.1 版本中更改:parse_constant 不再在 'null'、'true'、'false' 上呼叫。

要使用自定義的 JSONDecoder 子類,請使用 cls kwarg 指定;否則將使用 JSONDecoder。其他關鍵字引數將傳遞給類的建構函式。

如果正在反序列化的資料不是有效的 JSON 文件,則會引發 JSONDecodeError

在 3.6 版本中更改:所有可選引數現在都是僅關鍵字引數

在 3.6 版本中更改:fp 現在可以是二進位制檔案。輸入編碼應為 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 文件的 strbytesbytearray 例項) 反序列化為 Python 物件,使用此 轉換表

其他引數的含義與 load() 中的相同。

如果正在反序列化的資料不是有效的 JSON 文件,則會引發 JSONDecodeError

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

object

dict

array

list

string

str

number (int)

int

number (real)

float

true

True

false

False

null

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

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 為 false(預設值),則當嘗試編碼不是 strintfloatNone 的鍵時,將引發 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.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 選項按鍵的字母順序對字典的輸出進行排序。

命令列選項

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

顯示幫助資訊。

腳註