json
— JSON 編碼器和解碼器¶
原始碼: Lib/json/__init__.py
JSON (JavaScript 物件表示法),由 RFC 7159 (它取代了 RFC 4627) 和 ECMA-404 指定,是一種受 JavaScript 物件字面量語法啟發的輕量級資料交換格式(儘管它不是 JavaScript 的嚴格子集 [1] )。
警告
解析來自不受信任來源的 JSON 資料時要小心。惡意的 JSON 字串可能會導致解碼器消耗大量的 CPU 和記憶體資源。建議限制要解析的資料的大小。
json
公開了一個 API,該 API 對於標準庫 marshal
和 pickle
模組的使用者來說是熟悉的。
編碼基本 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
值(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 版本中更改:所有可選引數現在都是僅關鍵字引數。
- 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。
編碼器和解碼器¶
- 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 (一個包含 JSON 文件的
str
例項)的 Python 表示形式。如果給定的 JSON 文件無效,將引發
JSONDecodeError
。
- 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(預設值),則當嘗試編碼不是
str
、int
、float
或None
的鍵時,將引發TypeError
。 如果 skipkeys 為 true,則會跳過此類項。如果 ensure_ascii 為 true (預設),則保證輸出將所有傳入的非 ASCII 字元進行轉義。 如果 ensure_ascii 為 false,這些字元將按原樣輸出。
如果 check_circular 為 true(預設值),則會在編碼期間檢查列表、字典和自定義編碼物件中的迴圈引用,以防止無限遞迴(這會導致
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)
異常¶
標準合規性和互操作性¶
JSON 格式由 RFC 7159 和 ECMA-404 指定。本節詳細介紹了此模組與 RFC 的合規性級別。為簡單起見,不考慮 JSONEncoder
和 JSONDecoder
子類以及明確提到的引數以外的引數。
此模組不嚴格遵守 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
、-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_pairs_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
值,或者序列化“奇異”數值型別的例項(例如 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¶
顯示幫助資訊。
腳註