shelveは任意のPythonオブジェクトインスタンスコードを永続化するために使用される

6566 ワード

shelve--任意のPythonオブジェクトを永続化
ここ数日、Pythonのshelveというmoduleに触れましたが、pickleよりも使いやすい感じで、Pythonオブジェクトを永続化するための簡単なツールでもあります.プログラムを書くときにリレーショナル・データベースほどの重量級のものでデータを格納したくない場合は、shelveを試してみてください.shelfもkeyでアクセスし、辞書と似ています.shelve実用anydbmはDBを作成し、永続化オブジェクトを管理します.
新しい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

以上の2つの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 "\033[1;31;40mUsername '%s' doesn't existed\033[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 "\033[1;31;40mYou already logged in at: \033[0m" % datetime.datetime.fromtimestamp(last_login_time).isoformat()

    db[name]['last_login_time'] = login_time
    print "\033[1;32;40mwelcome back\033[0m", name
  else:
    print "\033[1;31;40mlogin incorrect\033[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()

本文を読むことに感謝して、みんなを助けることができることを望んで、みんなの当駅に対する支持に感謝します!