python--資料持久化
阿新 • • 發佈:2019-01-07
python中與資料持久化有關的模組有很多,像pickle、json之類的就不介紹了,這裡介紹兩個其他的模組:dbm和shelve
1.dbm
''' 在一些小型程式中,不需要關係型資料庫時,可以方便的用持久字典來儲存鍵值對,和python中的字典非常類似。而且dbm的鍵和值都必須是str或者bytes型別 ''' import dbm ''' 這裡第一個引數直接傳入檔名,第二個引數表示模式 常見的模式: r:可讀,預設就是這個模式 w:可讀可寫 但是r、w,都必須確保檔案已經存在,否則報錯。 c:可讀可寫,檔案不存在時會建立 n:可讀可寫,但總是會建立一個新的檔案,也就是說如果建立同名檔案,那麼之前的內容都會被清空,也就是起不到追加的效果。 因此我們平常的模式一般都會選擇c 第三個引數是許可權,這個在windows下基本不用,是一組用八進位制表示的數字,預設是0o666,都是可讀可寫不可執行 ''' db = dbm.open("store", "c") # 開啟檔案之後,就可以儲存值了 # 注意key和value都必須是str或者bytes型別 db["name"] = "satori" db["age"] = "16" db["gender"] = "f" db["anime"] = "東方地靈殿" # 關閉檔案,將內容寫到磁碟上 db.close() ################################################################ # 開啟檔案 db = dbm.open("store", "c") print(db.keys()) # [b'name', b'age', b'gender', b'anime'] for key in db.keys(): print(f"key={key}, value={db[key]}") ''' key=b'name', value=b'satori' key=b'age', value=b'16' key=b'gender', value=b'f' key=b'anime', value=b'\xe4\xb8\x9c\xe6\x96\xb9\xe5\x9c\xb0\xe7\x81\xb5\xe6\xae\xbf' '''
會多出這麼三個檔案
2.shelve
''' shelve和dbm比較類似,但是功能遠比dbm強大,因為它可以持久化任意物件 ''' import shelve # 引數flag預設是c,因此我們只需要傳入檔名就可以了,這個是自動追加在後面的 # 也就是說我寫完之後,再次開啟繼續寫的話,只會追加不會清空 sh = shelve.open("shelve") sh["dict"] = {"name": "satori", "age": 16} sh["list"] = [1, 2, 3, 4] sh["set"] = {1, 2, 3, 2} # 寫完之後關閉檔案,刷到記憶體裡面 # 關閉之後就無法操作了 sh.close() # 下面我們就可以操作資料了,下面的程式碼即便寫在另一個py檔案裡面也是可以的 sh2 = shelve.open("shelve") print(sh2["dict"], sh2["dict"].keys()) # {'name': 'satori', 'age': 16} dict_keys(['name', 'age']) print(sh2["list"], sum(sh2["list"])) # [1, 2, 3, 4] 10 print(sh2["set"]) # {1, 2, 3} sh2.close() # 可以看到,拿出來的就是原生的物件,可以直接用來進行操作的。那我們看看自己定義的類可不可以呢? sh3 = shelve.open("shelve") class A: def __init__(self, name, age): self.name = name self.age = age @property def print_info(self): return f"my name is {self.name}, age is {self.age}" a = A("satori", 16) # 將這個類和類的一個例項物件儲存進去 sh3["A"] = A sh3["a"] = a sh3.close() ###################################### sh4 = shelve.open("shelve") # sh4["A"]拿到A這個類,傳入引數,呼叫方法 print(sh4["A"]("mashiro", "17").print_info) # my name is mashiro, age is 17 # sh4["a"]拿到a這個例項物件,直接呼叫方法 print(sh4["a"].print_info) # my name is satori, age is 16 # 我們發現依舊是可以的,說明了shelve這個模組真的很強大
# 我們再來看一個例子 import shelve sh = shelve.open("shelve") sh["list"] = [1, 2, 3] sh["str"] = "mashiro" sh.close() ############################## sh = shelve.open("shelve") sh["list"].append("xxxx") sh["str"] = "satori" sh.close() ####################### sh = shelve.open("shelve") print(sh["list"]) # [1, 2, 3] print(sh["str"]) # satori ''' 分析結果,第一次開啟檔案我們建立兩個鍵值對 sh["list"] = [1, 2, 3] sh["str"] = "mashiro" 第二次開啟檔案,修改了兩個鍵的值 第三次開啟檔案,列印。但是我們發現sh["str"]改變了,但是sh["list"]沒有改變,這是為什麼? 首先sh["str"] = "satori"很好理解,但是為什麼sh["list"]沒有變? 因為=,我們是直接賦值,將這一塊記憶體裡面的值給換掉,而sh["list"]我們是做append操作,這只是在原來的基礎上進行修改 shelve預設情況下是不會記錄,持久化物件的修改的,除非你是建立新的物件,或者是把原來的物件給換掉 如果是在原來的基礎上(可變型別),比如列表、字典,進行新增或者刪除操作,這些是不會被記錄的 所以:sh["list"]=[1, 2, 3] sh["list"].append("xxxx") --->sh["list"]仍是[1, 2, 3]不會是[1, 2, 3, "xxx"] 因為shelve沒有記錄物件自身的修改,如果我想得到期望的結果,一種方法是把物件整體換掉 sh["list"] = [1, 2, 3, "xxxx"],這樣等於是重新賦值,是可行的。但是有時候我們不知道列表裡面內容,或者列表裡面的內容是一些函式、類什麼的、不好寫的話,該咋辦呢? 其實我們在開啟檔案的時候,還可以加上一個引數,叫做writeback '''
import shelve sh = shelve.open("shelve") sh["list"] = [1, 2, 3] sh["str"] = "mashiro" sh.close() ############################## # 如果我們需要進行修改,那麼加上一個writeback=True就可以了,從名字也能看出來 # 這是會將修改的內容從新寫回去 sh = shelve.open("shelve", writeback=True) sh["list"].append("xxxx") sh["str"] = "satori" sh.close() ####################### sh = shelve.open("shelve") print(sh["list"]) # [1, 2, 3, 'xxxx'] print(sh["str"]) # satori ''' 可以看到都發生改變了,但是這個引數有缺陷,就是會有額外的記憶體消耗。當我們加上writeback=True的時候shelve會將我們讀取的物件都放到一個記憶體快取當中。 比如說我們獲取了20持久化的物件,但是我們只修改了一個,剩餘的19個只是檢視並沒有做修改,但當我們sh.close()的時候,會將這20個物件都寫回去 因為shelve不知道你會對哪個物件進行修改,於是不管你是檢視還是修改,都會放到快取當中,然後再一次性都寫回去。 這樣會造成兩點: 1.物件放到記憶體快取當中,等於是重新拷貝了一份,因為我們讀取檔案已經到記憶體當中了,而shelve又把我們使用的物件放當記憶體的另一片空間中 2.寫入資料,我們明明只修改了一份資料,但是它把20份都重新寫回去了,這樣會造成效能上的問題,導致效率會降低。 因此加不加這個引數,由具體情況決定 '''