python 歷險記(四)— python 中常用的 json 操作

ReyCG發表於2018-11-16

引言

你一定聽說過 JSON 吧。JSON 是當前最常用的資料傳輸格式之一,純文字,容易使用,方便閱讀,最重要的是在多個場合都被大量被使用。

既然 JSON 這麼好,那就讓我們繼續探險,去掌握 python 中對 JSON 的常用操作吧, okay, let`s go!

基礎知識

莊子曰:“水之積也不厚,則其負大舟也無力。”。要完全掌握一個知識點,先將這個知識點需要的基礎知識補齊,這樣學的才能牢固。

下面就是我認為學習對 JSON 操作前的知識點。如果您對這部分已經瞭然於胸,儘可以略過這部分,跳到下一節。

什麼是 JSON?

Json (Javascript Object Notation) 是一種輕量級的資料交換格式,它基於 Javascript 的物件字面量。儘管它只是 Javascript 的一個子集,但它與語言無關。以現代程式語言編寫的程式,都可以用它來彼此交換資料。它是一種文字格式,人和機器都可以閱讀它。

—— 《Javascript 語言精粹》

既然以現代程式語言都可以用它來交換資料,強大的 python 當然也不例外。要更好的使用 JSON 一定要先了解下它的語法。

JSON 的語法

JSON 的值分為 6 種型別,分別是物件,陣列,字串,數字,布林值 (truefalse )和null。來看一個典型的 JSON 集合,體會下這些型別。

{
  "obj": {
    "name": "xxx",
    "address": {
      "country": "china",
      "city": "TianJin"
    }
  },
  "arr_simple": [1, 2, 3, 5],
  "arr_complex": [
    1,
    "a",
    {
      "b": "yyy"
    },
    true,
    null
  ],
  "str": "I am a string",
  "num": 888,
  "booValue": false,
  "nullValue": null
}

看上面程式碼, JSON 語法有什麼特點呢?

  1. JSON 字串必須使用 雙引號包圍
  2. 可以在任何值前後插入空白(包括空格,製表符,回車,換行),當然這些空白符也可以去除。

像字串,數字,布林值,null 都比較簡單,無需細數,接下來我們重點來看下物件和陣列。

JSON 物件有哪些特點?

JSON 物件的結構是什麼樣子呢?

上面程式碼中的 obj 就是一個 JSON 物件,我們來觀察下它。

  1. 它是用 {} 括起來的一個集合,每一項都包含名稱 ,如 name 就是名稱,而值就是 xxx
  2. 名稱可以是任意字串,但必須是字串才可以哦。
  3. 值只要是上面 6 種型別之一就可以
  4. 名稱/值 對沒有固定的順序,可以是任意順序
  5. 可以支援無限層的巢狀,如 obj 物件中巢狀了一個 address 物件,但是為了保證處理的高效性,請儘量保持結構的扁平性,也就是不要巢狀太多層哦)

為了能夠處理 JSON 資料,許多語言都有對應的資料型別可以對映為 JSON 物件,那麼 python 中是什麼資料型別呢?

dict ,如果有您對 dict 有些遺忘了,就請到這裡複習下吧。

JSON 陣列有哪些特點?

上面程式碼中的 arr_simplearr_complex 都表示陣列,它們有哪些特點呢?

  • 是一個 有序序列
  • 只有 組成
  • 值可以是任意型別的 JSON 值,如 arr_complex 陣列。

python 也有能夠對映為 JSON 物件的資料型別,是 listtuple , 如果您對 listtuple 的特性有些生疏了,也可以在這裡回顧下。

什麼是編碼和解碼?

說到 JSON 和 python 之間的轉換,就會涉及到兩個名詞:編碼解碼

那麼到底什麼是編碼和解碼呢?

編碼資訊從一種形式格式轉換為另一種形式的過程。解碼,是編碼的逆過程,亦即把編碼過的資訊恢復成原來樣式。

——維基百科

編碼的作用則是為了利於傳輸和儲存,JSON 當然是非常適合的。因此,

  • 把 python 物件轉換成 JSON 的過程就稱為編碼
  • 把 JSON 轉換成 python 物件的過程就稱為解碼

常用的 json 操作有哪些?

剛開始接觸 json 的操作,我主要有下面幾個疑問:

  • json 操作需要什麼庫?
  • 如何將 python 物件轉換成 JSON字串,更進一步,能不能直接轉換成檔案控制程式碼儲存到檔案中?(編碼)
  • 如何將 json 字串轉換成 python 物件,更進一步,能不能直接將 JSON 格式的檔案轉換成 python 物件?(解碼)

下面就讓我們一一來探索這些問題。

json 操作需要什麼庫?

使用 json 函式前需要先匯入 json 庫:

import json

json 庫本身就是 python 內建的標準庫,因此你不需要做任何安裝的操作。只要宣告瞭上面語句,就可直接使用。

如何將 python 編碼成 JSON?

python 編碼為 JSON 的對照表

要完成這個功能,先要看下 python 資料結構編碼為 json 的對照表。

Python JSON
dict object
list, tuple array
str string
int, float, int- & float-derived Enums number
True true
False false
None null

有了這張表,我們就可以清楚的知道 python 物件將編碼成的 json 格式。

json.dumps()

json.dumps() 方法的作用就是將 python 物件轉換成 JSON 字串,下面來看具體的函式宣告:

json.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding="utf-8", default=None, sort_keys=False, **kw)

引數看起來好多啊,不過不用擔心,這麼多引數,只有第一個引數是必填的。下面就來一一瞭解下這些引數的意義

  • obj 就是要編碼的 python 物件
  • skipkeys 預設值是 False。設定為 True ,假如 obj 中的 dict keys 不是基本型別(str , int , float , bool , None ), 就會被忽略,而不是丟擲 TypeError 錯誤
  • ensure_ascii 預設是 True , 表示預設使用ascii 編碼。如果 obj 內含有非 ASCII 字元,就會出現 “uXXXX” 格式顯式的資料, 設定成 False 就會使用字元本來的編碼。
    • 這裡要注意,如果輸入是中文,需要指定 ensure_ascii=False
  • check_circular 預設值是 True,如果設定為 False 就不會檢查內部型別是否包含迴圈引用,而且迴圈引用會導致 OverflowError
  • allow_nan 預設值為 False ,如果碰到超過範圍的 float 值(nan, inf, -inf )就使用 (NaN,Infinity, -Infinity) 替換
    • 如果為 True 碰到這些值則會導致 ValueError
  • indent 縮排設定
    • 如果是非負整數或者 string, JSON Array 元素和物件元素將會按照設定的縮排格式化顯示
    • 值為 0, 負值,或者 "" 只會插入新的一行
    • 值為 None (也是預設值)會盡可能的壓縮
  • separators 分隔符。
    • 如果要設定它,引數需要是一個元組(item_separator, key_separator)
    • 預設值是 (`, `, `: `) ,表示 keys 之間用 , 隔開,而 key 和 value 之間用 : 隔開
  • sort_keys 預設值是 False ,如果設定成 True , dict 結構的輸出就會按照 key 來排序
  • encoding 預設值是 UTF-8 用於設定 JSON 資料的編碼方式,在處理中文時這裡一定要注意。

來看一個例子

>>> import json
>>> json.dumps([`foo`, {`bar`: (`baz`, None, 1.0, 2)}])
`["foo", {"bar": ["baz", null, 1.0, 2]}]`
>>> print(json.dumps(""fooar"))
""fooar"
>>> 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}

json.dump()

json.dump() 函式的作用就是將 python 物件轉換成 JSON 字串,並將其通過 fp 檔案流寫入到檔案中。來看下具體的函式宣告:

 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)

和前面的 dumps 函式進行比較,會發現兩個函式的引數是非常相似的,而且它們的意義也都相同。來看下面的例子

>>> import json
>>> from io import StringIO
>>> io = StringIO()
>>> json.dump([`streaming API`], io)
>>> io.getvalue()
`["streaming API"]`

如何將 JSON 解碼成 python 物件?

JSON 解碼為 python 的對照表

要完成這個功能,也先要看下 json 解碼為 python 物件的對照表

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

編碼對照表和解碼對照表並不是一一對應的,因此如果一個 python物件 先編碼成 JSON,再轉碼回來後得到的物件可就不一定完全相等了。

json.loads()

這個方法的作用就是將引數 s 按照上面的對照表反序列化為一個 python 物件。引數 s 可以是 str ,byte 或者byteArray 格式, 但必須要包含 JSON 文字才可以)。具體函式宣告如下:

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

下面就來一一瞭解下一些常用引數的意義

  • s 就是要解碼的 python 字串
  • encoding 指定編碼格式
  • parse_float ,預設情況下相當於 float(num_str)。如果設定為其他值,將會把一個 JSON 字串按照 float 解碼呼叫,
  • parse_int ,預設情況下相當於 int(num_str),如果指定,將把每個 JSON 字串按照 int 解碼呼叫

來看下面的例子,其中最後一行就指定了 parse_float

>>> import json
>>> json.loads(`["foo", {"bar":["baz", null, 1.0, 2]}]`)
[`foo`, {`bar`: [`baz`, None, 1.0, 2]}]
>>> json.loads(`"\"foo\bar"`)
`"foox08ar`
>>> import decimal
>>> json.loads(`1.1`, parse_float=decimal.Decimal)
Decimal(`1.1`)

json.load()

先來看函式宣告

 json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

作用是將 fp 檔案流反序列化為 python 物件,其中的引數意義和 loads 方法相同。來看一個例子。

>>> import json
>>> from io import StringIO
>>> io = StringIO(`["streaming API"]`)
>>> json.load(io)
[`streaming API`]

結語

本文主要介紹了 JSON 的定義,語法以及 JSON 的常用操作。但是並沒有涉及 JSON 處理自定義資料型別的高階內容(JSONEncoderJSONDecoder),這部分內容會再後面的篇章中專門介紹。

下篇會介紹 python 的模組,敬請期待。

參考文件

  1. python json API Library
  2. 《Javascript 語言精粹》
  3. 編碼—維基百科

相關文章列表

相關文章