json
--- JSON 編碼器與解碼器¶
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({'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', ']']
在命令列介面裡使用 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)¶
參考這個轉換表將 obj 序列化為符合 JSON 格式的串流,並寫入到 fp (一個支援
.write()
方法的 file-like object)如果 skipkeys 被設為 true(預設值:
False
),那麼非基本型別(str
、int
、float
、bool
、None
)的 dictionary(字典)鍵值將被略過而不會引發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 指定該類別物件;否則預設使用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 是一個可選引數,其接受一個函式作為輸入。原始的有序對串列(ordered list of pairs)解碼結果將被傳入這個函式、並使用 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 版的變更: 預設 parse_int 使用的
int()
函式現在有限制整數字串的長度上限了,限制由直譯器的整數字串轉換長度限制機制來達成,這能防止阻斷服務攻擊 (Denial of Service attacks)。parse_constant 為可選函式,在解碼時若遭遇字串
'-Infinity'
、'Infinity'
或'NaN'
其中之一則會改用這個參數給定的函式來進行解碼。這也可用於使解碼過程中遇到無效的 JSON 數字時引發一個例外。在 3.1 版的變更: 遭遇 'null'、'true' 或 'false' 時不再以 parse_constant 給定的函式來處理了。
若想要使用自訂的
JSONDecoder
子類別物件,請以cls
關鍵字引數指定之,否則將使用預設的JSONDecoder
。其他未使用到的關鍵字引數將繼續傳入給 JSONDecoder 的建構函式使用。如果被去序列化(deserialized)的資料不符合 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 文件的
str
、bytes
或bytearray
的實例(instance))去序列化(deserialize)為一個 Python 物件其餘引數的使用方式與意義和
load()
的相同。如果被去序列化(deserialized)的資料不符合 JSON 格式,將會引發
JSONDecodeError
例外。在 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 規範,但解碼器依然能正確地將其轉換到相應的 Pythonfloat
值。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
例外。
- 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
例外)。若 skipkeys 為 false(預設值),則當在編碼不是
str
、int
、float
或None
的鍵值時,將引發TypeError
。如果 skipkeys 為 true,這些項目將直接被跳過。如果 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)
例外¶
合規性與互通性(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¶
顯示說明訊息。
註解