1. 程式人生 > >shelve -- 用來持久化任意的Python對象(轉)

shelve -- 用來持久化任意的Python對象(轉)

src 缺省 alt 開始 log 因此 每一個 gpo plain

這幾天接觸了Python中的shelve這個module,感覺比pickle用起來更簡單一些,它也是一個用來持久化(序列化)Python對象的簡單工具。當我們寫程序的時候如果不想用關系數據庫那麽重量級的東東去存儲數據,不妨可以試試用shelve。shelf也是用key來訪問的,使用起來和字典類似。shelve其實用anydbm去創建DB並且管理持久化對象的。

創建一個新的shelf

直接使用shelve.open()就可以創建了

技術分享圖片
1 import shelve
2 
3 s = shelve.open(test_shelf.db)
4 try:
5     s[key1] = { 
int: 10, float:9.5, string:Sample data } 6 finally: 7 s.close()
技術分享圖片

如果想要再次訪問這個shelf,只需要再次shelve.open()就可以了,然後我們可以像使用字典一樣來使用這個shelf

技術分享圖片
1 import shelve
2 
3 s = shelve.open(test_shelf.db)
4 try:
5     existing = s[key1]
6 finally:
7     s.close()
8 
9 print existing
技術分享圖片

當我們運行以上兩個py,我們將得到如下輸出:

$ python shelve_create.py
$ python shelve_existing.py

{int: 10, float: 9.5, string: Sample data}

dbm這個模塊有個限制,它不支持多個應用同一時間往同一個DB進行寫操作。所以當我們知道我們的應用如果只進行讀操作,我們可以讓shelve通過只讀方式打開DB:

技術分享圖片
1 import shelve
2 
3 s = shelve.open(test_shelf.db, flag=r)
4 try:
5     existing = s[key1]
6 finally:
7 s.close() 8 9 print existing
技術分享圖片

當我們的程序試圖去修改一個以只讀方式打開的DB時,將會拋一個訪問錯誤的異常。異常的具體類型取決於anydbm這個模塊在創建DB時所選用的DB。

寫回(Write-back)

由於shelve在默認情況下是不會記錄待持久化對象的任何修改的,所以我們在shelve.open()時候需要修改默認參數,否則對象的修改不會保存。

技術分享圖片
 1 import shelve
 2 
 3 s = shelve.open(test_shelf.db)
 4 try:
 5     print s[key1]
 6     s[key1][new_value] = this was not here before
 7 finally:
 8     s.close()
 9 
10 s = shelve.open(test_shelf.db, writeback=True)
11 try:
12     print s[key1]
13 finally:
14     s.close()
技術分享圖片

上面這個例子中,由於一開始我們使用了缺省參數shelve.open()了,因此第6行修改的值即使我們s.close()也不會被保存。

執行結果如下:

$ python shelve_create.py
$ python shelve_withoutwriteback.py

{int: 10, float: 9.5, string: Sample data}
{int: 10, float: 9.5, string: Sample data}

所以當我們試圖讓shelve去自動捕獲對象的變化,我們應該在打開shelf的時候將writeback設置為True。當我們將writeback這個flag設置為True以後,shelf將會將所有從DB中讀取的對象存放到一個內存緩存。當我們close()打開的shelf的時候,緩存中所有的對象會被重新寫入DB。

技術分享圖片
 1 import shelve
 2 
 3 s = shelve.open(test_shelf.db, writeback=True)
 4 try:
 5     print s[key1]
 6     s[key1][new_value] = this was not here before
 7     print s[key1]
 8 finally:
 9     s.close()
10 
11 s = shelve.open(test_shelf.db, writeback=True)
12 try:
13     print s[key1]
14 finally:
15     s.close()
技術分享圖片

writeback方式有優點也有缺點。優點是減少了我們出錯的概率,並且讓對象的持久化對用戶更加的透明了;但這種方式並不是所有的情況下都需要,首先,使用writeback以後,shelf在open()的時候會增加額外的內存消耗,並且當DB在close()的時候會將緩存中的每一個對象都寫入到DB,這也會帶來額外的等待時間。因為shelve沒有辦法知道緩存中哪些對象修改了,哪些對象沒有修改,因此所有的對象都會被寫入。

技術分享圖片
1 $ python shelve_create.py
2 $ python shelve_writeback.py
3 
4 {int: 10, float: 9.5, string: Sample data}
5 {int: 10, new_value: this was not here before, float: 9.5, string: Sample data}
6 {int: 10, new_value: this was not here before, float: 9.5, string: Sample data}
技術分享圖片

最後再來個復雜一點的例子:

技術分享圖片
 1 #!/bin/env python
 2 
 3 import time
 4 import datetime
 5 import md5
 6 import shelve
 7 
 8 LOGIN_TIME_OUT = 60
 9 db = shelve.open(user_shelve.db, writeback=True)
10 
11 def newuser():
12     global db
13     prompt = "login desired: "
14     while True:
15         name = raw_input(prompt)
16         if name in db:
17             prompt = "name taken, try another: "
18             continue
19         elif len(name) == 0:
20             prompt = "name should not be empty, try another: "
21             continue
22         else:
23             break
24     pwd = raw_input("password: ")
25     db[name] = {"password": md5_digest(pwd), "last_login_time": time.time()}
26     #print ‘-->‘, db
27 
28 def olduser():
29     global db
30     name = raw_input("login: ")
31     pwd = raw_input("password: ")
32     try:
33         password = db.get(name).get(password)
34     except AttributeError, e:
35         print "\033[1;31;40mUsername ‘%s‘ doesn‘t existed\033[0m" % name
36         return
37     if md5_digest(pwd) == password:
38         login_time = time.time()
39         last_login_time = db.get(name).get(last_login_time)
40         if login_time - last_login_time < LOGIN_TIME_OUT:
41             print "\033[1;31;40mYou already logged in at: <%s>\033[0m" % datetime.datetime.fromtimestamp(last_login_time).isoformat()
42 
43         db[name][last_login_time] = login_time
44         print "\033[1;32;40mwelcome back\033[0m", name
45     else:
46         print "\033[1;31;40mlogin incorrect\033[0m"
47 
48 def md5_digest(plain_pass):
49    return md5.new(plain_pass).hexdigest()
50 
51 def showmenu():
52     #print ‘>>>‘, db
53     global db
54     prompt = """
55 (N)ew User Login
56 (E)xisting User Login
57 (Q)uit
58 Enter choice: """
59     done = False
60     while not done:
61         chosen = False
62         while not chosen:
63             try:
64                 choice = raw_input(prompt).strip()[0].lower()
65             except (EOFError, KeyboardInterrupt):
66                 choice = "q"
67             print "\nYou picked: [%s]" % choice
68             if choice not in "neq":
69                 print "invalid option, try again"
70             else:
71                 chosen = True
72 
73         if choice == "q": done = True
74         if choice == "n": newuser()
75         if choice == "e": olduser()
76     db.close()
77 
78 if __name__ == "__main__":
79     showmenu()
技術分享圖片

文章出處:https://www.cnblogs.com/frankzs/p/5949645.html

shelve -- 用來持久化任意的Python對象(轉)