zoukankan      html  css  js  c++  java
  • shelve -- 用来持久化任意的Python对象

    shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式

    创建一个新的shelf

    直接使用shelve.open()就可以创建了
    复制代码

     import shelve
    
     s = shelve.open('test_shelf.db')
     try:
         s['key1'] = { 'int': 10, 'float':9.5, 'string':'Sample data' }
     finally:
         s.close()

    如果想要再次访问这个shelf,只需要再次shelve.open()就可以了,然后我们可以像使用字典一样来使用这个shelf
    复制代码

     import shelve
    
     s = shelve.open('test_shelf.db')
     try:
         existing = s['key1']
     finally:
         s.close()
    
    print existing

    当我们运行以上两个py,我们将得到如下输出:

    $ python shelve_create.py
    $ python shelve_existing.py
    {'int': 10, 'float': 9.5, 'string': 'Sample data'}

    dbm这个模块有个限制,它不支持多个应用同一时间往同一个DB进行写操作。所以当我们知道我们的应用如果只进行读操作,我们可以让shelve通过只读方式打开DB:

     import shelve
    
     s = shelve.open('test_shelf.db', flag='r')
     try:
         existing = s['key1']
     finally:
         s.close()
    
     print existing

    当我们的程序试图去修改一个以只读方式打开的DB时,将会抛一个访问错误的异常。异常的具体类型取决于anydbm这个模块在创建DB时所选用的DB。

    写回(Write-back)

    由于shelve在默认情况下是不会记录待持久化对象的任何修改的,所以我们在shelve.open()时候需要修改默认参数,否则对象的修改不会保存。
    复制代码

      import shelve
    
      s = shelve.open('test_shelf.db')
      try:
          print s['key1']
          s['key1']['new_value'] = 'this was not here before'
      finally:
          s.close()
    
     s = shelve.open('test_shelf.db', writeback=True)
     try:
         print s['key1']
     finally:
         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。
    复制代码

      import shelve
    
      s = shelve.open('test_shelf.db', writeback=True)
      try:
          print s['key1']
          s['key1']['new_value'] = 'this was not here before'
          print s['key1']
      finally:
          s.close()
    
     s = shelve.open('test_shelf.db', writeback=True)
     try:
         print s['key1']
     finally:
         s.close()

    writeback方式有优点也有缺点。优点是减少了我们出错的概率,并且让对象的持久化对用户更加的透明了;但这种方式并不是所有的情况下都需要,首先,使用writeback以后,shelf在open()的时候会增加额外的内存消耗,并且当DB在close()的时候会将缓存中的每一个对象都写入到DB,这也会带来额外的等待时间。因为shelve没有办法知道缓存中哪些对象修改了,哪些对象没有修改,因此所有的对象都会被写入。
    复制代码

     $ python shelve_create.py
     $ python shelve_writeback.py
     {'int': 10, 'float': 9.5, 'string': 'Sample data'}
     {'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}
     {'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}

    最后再来个复杂一点的例子:
    复制代码

     #!/bin/env python
    
     import time
     import datetime
     import md5
     import shelve
    
     LOGIN_TIME_OUT = 60
     db = shelve.open('user_shelve.db', writeback=True)
    
     def newuser():
         global db
         prompt = "login desired: "
         while True:
             name = raw_input(prompt)
             if name in db:
                 prompt = "name taken, try another: "
                 continue
             elif len(name) == 0:
                 prompt = "name should not be empty, try another: "
                 continue
             else:
                 break
         pwd = raw_input("password: ")
         db[name] = {"password": md5_digest(pwd), "last_login_time": time.time()}
         #print '-->', db
    
     def olduser():
         global db
         name = raw_input("login: ")
         pwd = raw_input("password: ")
         try:
             password = db.get(name).get('password')
         except AttributeError, e:
             print "33[1;31;40mUsername '%s' doesn't existed33[0m" % name
             return
         if md5_digest(pwd) == password:
             login_time = time.time()
             last_login_time = db.get(name).get('last_login_time')
             if login_time - last_login_time < LOGIN_TIME_OUT:
                 print "33[1;31;40mYou already logged in at: <%s>33[0m" % datetime.datetime.fromtimestamp(last_login_time).isoformat()
    
             db[name]['last_login_time'] = login_time
             print "33[1;32;40mwelcome back33[0m", name
         else:
             print "33[1;31;40mlogin incorrect33[0m"
    
     def md5_digest(plain_pass):
        return md5.new(plain_pass).hexdigest()
    
     def showmenu():
         #print '>>>', db
         global db
         prompt = """
     (N)ew User Login
     (E)xisting User Login
     (Q)uit
     Enter choice: """
         done = False
         while not done:
             chosen = False
             while not chosen:
                 try:
                     choice = raw_input(prompt).strip()[0].lower()
                 except (EOFError, KeyboardInterrupt):
                     choice = "q"
                 print "
    You picked: [%s]" % choice
                 if choice not in "neq":
                     print "invalid option, try again"
                 else:
                     chosen = True
    
             if choice == "q": done = True
             if choice == "n": newuser()
             if choice == "e": olduser()
         db.close()
    
     if __name__ == "__main__":
         showmenu()
     转自:https://www.cnblogs.com/frankzs/p/5949645.html
    
  • 相关阅读:
    [Luogu P3626] [APIO2009] 会议中心
    杭电 1869 六度分离 (求每两个节点间的距离)
    杭电 1874 畅通工程续 (求某节点到某节点的最短路径)
    最短路径模板
    杭电 2544 最短路径
    POJ 1287 Networking (最小生成树模板题)
    NYOJ 1875 畅通工程再续 (无节点间距离求最小生成树)
    POJ 2485 Highways (求最小生成树中最大的边)
    杭电 1233 还是畅通工程 (最小生成树)
    杭电 1863 畅通工程 (最小生成树)
  • 原文地址:https://www.cnblogs.com/tylf-lk/p/10133475.html
Copyright © 2011-2022 走看看