Python入門系列25 - 你真的了解JSON嘛?
Python入門系列25

你真的了解JSON嘛?
本篇閱讀時(shí)間約為6分鐘。
1
前言
原諒我標(biāo)題黨了一波,哈哈哈哈!其實(shí)今天這篇文章算是題外番了,為什么這么說呢?因?yàn)镴SON這個(gè)詞,在當(dāng)今的web環(huán)境下,作為一種最常使用的數(shù)據(jù)格式來進(jìn)行各處的交互,本想著不打算介紹JSON的,但是因?yàn)楹罄m(xù)的爬蟲章節(jié)肯定會(huì)涉及到這個(gè)知識(shí)點(diǎn),早就說過,此系列文章是為了讓小白也能入門……所以還是單獨(dú)提出來寫一篇文章來講解下。
2
JSON的概念
JSON,全拼JavaScript Object Notation, 中文是JavaScript 對象表示法的意思,它是一種輕量級的數(shù)據(jù)交換格式。來!劃重點(diǎn)……輕量級的!數(shù)據(jù)交換格式!概念上來說,這兩點(diǎn)是最重要的,也是最應(yīng)該記住的。
PS: JavaScript是前端的一種腳本語言,比如我們?yōu)g覽器的一些按鈕交互動(dòng)作,都是由JS來實(shí)現(xiàn)的。
3
JSON與XML的比較
再普及一個(gè)新的名詞知識(shí)點(diǎn)XML,早期傳遞數(shù)據(jù),是用XML來進(jìn)行傳遞的。等到后來JSON出來以后,越來越多的人開始使用JSON在網(wǎng)絡(luò)上進(jìn)行數(shù)據(jù)的傳遞了,當(dāng)然是因?yàn)镴SON比XML有更多的優(yōu)點(diǎn),才會(huì)被人們接受哇!⊙?⊙!

來看下面的兩個(gè)觀點(diǎn):
什么是 XML?
· XML 指可擴(kuò)展標(biāo)記語言(EXtensible Markup Language)
·?XML 是一種標(biāo)記語言,很類似 HTML
·?XML 的設(shè)計(jì)宗旨是傳輸數(shù)據(jù),而非顯示數(shù)據(jù)
什么是JSON?
·?JSON 是輕量級的文本數(shù)據(jù)交換格式
·?JSON 獨(dú)立于語言 *
·?JSON 具有自我描述性,更易理解
說了這么多,分別來看下二者長什么樣子吧!以下截圖來源皆來于網(wǎng)址:
http://www.w3school.com.cn,有興趣的可以去看下官方的講述。
圖1,XML:

學(xué)過HTML的同學(xué)看上去是不是非常熟悉,XML也是采用閉合標(biāo)簽的形式來標(biāo)記數(shù)據(jù)。
圖2,JSON:

而JSON呢?實(shí)則就是一串字符串,是不是看起來非常像Python的數(shù)據(jù)類型dict,也就是字典呢!
4
Python中JSON的用法
了解到上述所有概念后就好說多了,JSON在每種語言中都有著不同的數(shù)據(jù)類型相互對應(yīng),比如在Python中,當(dāng)我們把一個(gè)普通的JSON字符串解析完成后,得到的就是dict類型。口說無憑,來直接看下面的示例吧!
示例1:場景來咯,假設(shè)你的女朋友!被我用JSON字符串來描述她的特征了,那么現(xiàn)在需要將此JSON串,在python中將她的體重讀取到,改如何做呢?
首先import一個(gè)叫做json的內(nèi)置庫,python一向秉承著簡潔,通過名字就知道這個(gè)庫是做什么的啦!而json有個(gè)方法,可以將JSON數(shù)據(jù)格式直接轉(zhuǎn)化為python內(nèi)置的數(shù)據(jù)類型,調(diào)用loads方法來進(jìn)行轉(zhuǎn)化。下面就來看下具體代碼:
import?json
girlfriend_json1?=?"{name?:?女兒國公主?,?age?:?10000,?weight?:?200kg}"
girlfriend_json2?=?"{'name'?:?'女兒國公主'?,?'age'?:?10000,?'weight'?:?'200kg'}"
girlfriend_json3?=?'{"name"?:?"女兒國公主"?,?"age"?:?10000,?"weight"?:?"200kg"}'
girlfriend_dict?=?json.loads(girlfriend_json1)
girlfriend_dict?=?json.loads(girlfriend_json2)
girlfriend_dict?=?json.loads(girlfriend_json3)
print(type(girlfriend_dict))
print(girlfriend_dict)
可以看到代碼中,在設(shè)定JSON字符串時(shí),以女朋友的特性來作為JSON字符串的“key”,對應(yīng)的值來作為JSON字符串的"value"。那么問題來了,你認(rèn)為girlfriend_json1?~ 3 哪個(gè)才是正確的寫法呢?(先不要看下面的解釋喲,獨(dú)立思考下!)
解釋:
①?girlfriend_json1 ,大體格式是沒有錯(cuò)的,正如python中的dict一樣,JSON字符串也是有類似key-value這種形式組成的數(shù)據(jù)格式。但是,假設(shè)如果我們解析正常了,此時(shí)的name肯定是一個(gè)沒有經(jīng)過定義的變量,這樣的存在在程序中是不被允許的,所以肯定會(huì)報(bào)錯(cuò)!如下:

②?girlfriend_json2 ,有了1的解釋,那么我們可以得出一個(gè)結(jié)論,JSON中未定義的變量是不能直接命名的,所以必須用引號來修飾,也就是說要定義成字符串的形式來寫,于是呢有了2的寫法,繼續(xù)來運(yùn)行下看看能否成功呢?

這是為什么呢?已經(jīng)用單引號括起來了,還是報(bào)錯(cuò),實(shí)際上雖然在python中定義字符串是可以用單雙引號來修飾,但是請務(wù)必記住,JSON本身規(guī)定如此,在JSON自身中必須由雙引號去定義才算是屬性字符串。所以呢,所以呢,繼續(xù)看下面的3吧!
③?girlfriend_json3 ,此種寫法在1,2上層層優(yōu)化,得出的雙引號定義屬性,而對于數(shù)字來說,是不需要被雙引號括起來進(jìn)行修飾的,這點(diǎn)可以注意下,如下圖:

經(jīng)過不斷地調(diào)整,因?yàn)镴SON本身需要用雙引號來定義所謂的變量,所以在python中定一個(gè)JSON字符串,最外層就要用單引號來修飾,通過loads轉(zhuǎn)化成功后,可以看到轉(zhuǎn)成的數(shù)據(jù)類型是python中的dict類型!這里就非常容易可以將女票的體重讀取出出來了!只需要利用dict['key']操作即可。
示例2:場景再次變更,假設(shè)還是你的女朋友!一個(gè)前任,一個(gè)現(xiàn)任,需要作對比!依然是用JSON字符串來描述她們的特征,最終還是要在python中將她們的體重讀取到,改如何做呢?而這個(gè)JSON字符串該如何定義呢?(思考思考....)
import?json
girlfriend_json?=?'[{"name"?:?"前任女兒國公主"?,?"age"?:?10000,?"weight"?:?"200kg"},'?\
??????????????????'{"name"?:?"現(xiàn)任嫦娥小姐姐"?,?"age"?:?18,?"weight"?:?"50kg"}]'
girlfriend_list?=?json.loads(girlfriend_json)
print(type(girlfriend_list))
print(girlfriend_list)
print(f"前任的體重:{girlfriend_list[0]['weight']}")
print(f"現(xiàn)任的體重:{girlfriend_list[1]['weight']}")
在定義前任后,通過\ 對字符串的定義進(jìn)行了換行操作,要不實(shí)在是太長了!可以看到,通過[]將兩個(gè)JSON組合到了一起,但是依然是字符串形式,運(yùn)行下代碼,輸出看下結(jié)果:

可以看到,經(jīng)過類似python中l(wèi)ist的去定義JSON,在解析后,得到的python基礎(chǔ)數(shù)據(jù)類型就是list,而不是在示例一種解析得到的dict類型!
這也是為什么我又再次舉例了示例2的原因,JSON自身是有著所謂不同的“數(shù)據(jù)基礎(chǔ)類型”,而每一種都可以對應(yīng)到不同語言中去!(包括你可以進(jìn)行布爾值的嘗試)這就要涉及到另一個(gè)知識(shí)點(diǎn)了,序列化與反序列化。
PS:
附上一張三個(gè)語言的基礎(chǔ)類型比較。
| JSON | Python | Java |
|---|---|---|
| object(JSON整串) | dict | Map |
| array | list | List |
| string | str | String |
| number | int | int |
| number | float | float |
| true | True | true |
| false | False | false |
| null | None | null |
5
python的序列化與反序列化
1. 序列化
先來看下序列化是什么意思?實(shí)例如下:
示例:場景再次降臨,假設(shè)你的女朋友!前任和現(xiàn)任(捂臉逃,跟女朋友杠上了!汪汪汪……).....這次不定義在JSON上了,我們將其定義在python的基礎(chǔ)數(shù)據(jù)類型list中
....
import?json
girlfriend_list?=?[{'name':?'女兒國公主',?'age':?10000,?'weight':?'200kg'},
???????????????????{'name':?'嫦娥小姐姐',?'age':?18,?'weight':?'50kg'}
???????????????????]
#?ensure_ascii?=?False,此參數(shù)加上,中文才不會(huì)被轉(zhuǎn)為unicode編碼
girlfriend_json?=?json.dumps(girlfriend_list,ensure_ascii=False)
girlfriend_json2?=?json.dumps(girlfriend_list)
print(girlfriend_json)
print(girlfriend_json2)
print(type(girlfriend_json))

代碼中,通過json.dumps方法,將定義好的python基礎(chǔ)類型list轉(zhuǎn)為本章男豬腳JSON形式,打印輸出你可以看到,它其實(shí)就是一段字符串。
需要注意的是:如果你的內(nèi)容里包含了中文字符,在dumps方法里傳入第二個(gè)參數(shù),將ascii碼選項(xiàng)設(shè)置為False即可成功顯示原有中文,否則默認(rèn)為True,中文會(huì)被轉(zhuǎn)為unicode進(jìn)行輸出。此處所說可以點(diǎn)擊上圖查看到結(jié)果的輸出案例。
以上說了這么多,實(shí)際上我們將程序內(nèi)存中的基礎(chǔ)數(shù)據(jù)類型轉(zhuǎn)為JSON的這一過程,就稱之為序列化。
序列化的目的:序列化之后,就可以把序列化后的內(nèi)容寫入磁盤,或者通過網(wǎng)絡(luò)傳輸?shù)絼e的機(jī)器上,也就是所謂的數(shù)據(jù)落地(落地,寫入數(shù)據(jù)庫中或者電腦磁盤上)與數(shù)據(jù)調(diào)用傳輸。
2.?反序列化
反序列化就是將序列化的過程反過來,實(shí)際上并不難以理解,在上面我們將JSON轉(zhuǎn)化為Python內(nèi)置數(shù)據(jù)基礎(chǔ)類型的這個(gè)過程,其實(shí)就是稱之為反序列化。當(dāng)然這里不限定與JSON轉(zhuǎn)為Python的內(nèi)置數(shù)據(jù)類型,類似的,比如XML轉(zhuǎn)為Python數(shù)據(jù)類型的過程也可以稱之為反序列化。從硬件的思維角度解釋來說,就是將硬盤、網(wǎng)絡(luò)上的數(shù)據(jù)轉(zhuǎn)化為語言本身內(nèi)存的數(shù)據(jù)基礎(chǔ)類型來供程序使用。
6
關(guān)于JSON額外的一些話題
在網(wǎng)絡(luò)系統(tǒng)的交互中,像這種數(shù)據(jù)格式進(jìn)行交互來說是必不可少的,比如我們?nèi)粘I钪薪?jīng)常會(huì)用瀏覽器訪問網(wǎng)頁,拿淘寶舉例,它上面的物品價(jià)格數(shù)字有可能每天都會(huì)發(fā)生變化,而這些數(shù)據(jù)就是通過后端系統(tǒng)使用JSON這種數(shù)據(jù)格式將數(shù)據(jù)傳到頁面上,最終由瀏覽器動(dòng)態(tài)渲染而成,你才能看到每種商品都有不同的價(jià)錢。
如下圖:

好了,以上就是本章介紹的番外篇JSON啦。
至此完!
