1. 程式人生 > 實用技巧 >python常用模組:json&pickle

python常用模組:json&pickle

之前我們學習過用eval內建方法可以將一個字串轉成python物件,不過,eval方法是有侷限性的,對於普通的資料型別,json.loads和eval都能用,但遇到特殊型別的時候,eval就不管用了,所以eval的重點還是通常用來執行一個字串表示式,並返回表示式的值

一、序列化

  我們把物件(變數)從記憶體中變成可儲存或傳輸的過程稱之為序列化,在Python中叫pickling,在其他語言中也被稱之為serialization,marshalling,flattening等等,都是一個意思

二、為什麼要序列化

  1:持久儲存狀態需知一個軟體/程式的執行就在處理一系列狀態的變化,在程式語言中,'狀態'會以各種各樣有結構的資料型別(也可簡單的理解為變數)的形式被儲存在記憶體中。記憶體是無法永久儲存資料的,當  程式運行了一段時間,我們斷電或者重啟程式,記憶體中關於這個程式的之前一段時間的資料(有結構)都被清空了。在斷電或重啟程式之前將程式當前記憶體中所有的資料都儲存下來(儲存到檔案中),以便於下次程式執行能夠從檔案中載入之前的資料,然後繼續執行,這就是序列化。具體的來說,你玩使命召喚闖到了第13關,你儲存遊戲狀態,關機走人,下次再玩,還能從上次的位置開始繼續闖關。或如,虛擬機器狀態的掛起等。

  2:跨平臺資料互動序列化之後,不僅可以把序列化後的內容寫入磁碟,還可以通過網路傳輸到別的機器上,如果收發的雙方約定好實用一種序列化的格式,那麼便打破了平臺/語言差異化帶來的限制,實現了跨平臺資料互動。反過來,把變數內容從序列化的物件重新讀到記憶體裡稱之為反序列化,即unpickling。

三、json

  如果我們要在不同的程式語言之間傳遞物件,就必須把物件序列化為標準格式,比如XML,但更好的方法是序列化為JSON,因為JSON表示出來就是一個字串,可以被所有語言讀取,也可以方便地儲存到磁碟或者通過網路傳輸。JSON不僅是標準格式,並且比XML更快,而且可以直接在Web頁面中讀取,非常方便。

import json

dic={'name':'alvin','age':23,'sex':'male'}
print(type(dic))#<class 'dict'>

j=json.dumps(dic)
print(type(j))#<class 'str'>


f=open('序列化物件','w')
f.write(j)  #-------------------等價於json.dump(dic,f)
f.close()
#-----------------------------反序列化<br>
import json
f=open('序列化物件
') data=json.loads(f.read())# 等價於data=json.load(f)

需要注意的地方

import json
#dct="{'1':111}"#json 不認單引號
#dct=str({"1":111})#報錯,因為生成的資料還是單引號:{'one': 1}

dct='{"1":"111"}'
print(json.loads(dct))

#conclusion:
#        無論資料是怎樣建立的,只要滿足json格式,就可以json.loads出來,不一定非要dumps的資料才能loads

 注意點
注意點
# 在python直譯器2.7與3.6之後都可以json.loads(bytes型別),但唯獨3.5不可以
>>> import json
>>> json.loads(b'{"a":111}')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/linhaifeng/anaconda3/lib/python3.5/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'

瞭解
不同py版本的不同點
# 一.什麼是猴子補丁?
      猴子補丁的核心就是用自己的程式碼替換所用模組的原始碼,詳細地如下
  1,這個詞原來為Guerrilla Patch,雜牌軍、游擊隊,說明這部分不是原裝的,在英文裡guerilla發音和gorllia(猩猩)相似,再後來就寫了monkey(猴子)。
  2,還有一種解釋是說由於這種方式將原來的程式碼弄亂了(messing with it),在英文裡叫monkeying about(頑皮的),所以叫做Monkey Patch。


# 二. 猴子補丁的功能(一切皆物件)
  1.擁有在模組執行時替換的功能, 例如: 一個函式物件賦值給另外一個函式物件(把函式原本的執行的功能給替換了)
class Monkey:
    def hello(self):
        print('hello')

    def world(self):
        print('world')


def other_func():
    print("from other_func")



monkey = Monkey()
monkey.hello = monkey.world
monkey.hello()
monkey.world = other_func
monkey.world()

# 三.monkey patch的應用場景
如果我們的程式中已經基於json模組編寫了大量程式碼了,發現有一個模組ujson比它效能更高,
但用法一樣,我們肯定不會想所有的程式碼都換成ujson.dumps或者ujson.loads,那我們可能
會想到這麼做
import ujson as json,但是這麼做的需要每個檔案都重新匯入一下,維護成本依然很高
此時我們就可以用到猴子補丁了
只需要在入口處加上
, 只需要在入口加上:

import json
import ujson

def monkey_patch_json():
    json.__name__ = 'ujson'
    json.dumps = ujson.dumps
    json.loads = ujson.loads

monkey_patch_json() # 之所以在入口處加,是因為模組在匯入一次後,後續的匯入便直接引用第一次的成果

#其實這種場景也比較多, 比如我們引用團隊通用庫裡的一個模組, 又想豐富模組的功能, 除了繼承之外也可以考慮用Monkey
Patch.採用猴子補丁之後,如果發現ujson不符合預期,那也可以快速撤掉補丁。個人感覺Monkey
Patch帶了便利的同時也有搞亂原始碼的風險!

猴子補丁與ujson
猴子補丁與ujson