Kyoto CabinetをPythonで試す
はじめに
SQLが嫌いなので、TerminatterでMongoDB使ってるぽんこつさんだけど、気になったのでKey Value Store型で最も早い(らしい)Kyoto Cabinetを試そうかと思ったけど最初のexampleで躓いたお話。
Kyoto Cabinetのバインディングがダサい
Kyoto CabinetのExampleの1つを見て欲しい。
from kyotocabinet import * import sys # create the database object db = DB() # open the database if not db.open("casket.kch", DB.OWRITER | DB.OCREATE): print("open error: " + str(db.error()), file=sys.stderr) # store records if not db.set("foo", "hop") or \ not db.set("bar", "step") or \ not db.set("baz", "jump"): print("set error: " + str(db.error()), file=sys.stderr) # retrieve records value = db.get_str("foo") if value: print(value) else: print("get error: " + str(db.error()), file=sys.stderr) # traverse records cur = db.cursor() cur.jump() while True: rec = cur.get_str(True) if not rec: break print(rec[0] + ":" + rec[1]) cur.disable() # close the database if not db.close(): print("close error: " + str(db.error()), file=sys.stderr)
超絶にダサい。何がダサいかというと、
- ifで返り値をチェックしてエラー検出している。Python使いなら例外を返すべき
- cursorがもうどこから突っ込んでいいのか分からないぐらい酷い。MongoDBみたくiterator(みたいなforで回せるもの)を返すべき
- hop, step, jumpって何だ、spam, ham, eggに決まってるだろ!
といった辺り。
バインディングのラッパー
PythonianがPythonらしいバインディングに書き換えるラッパーを書いてみた。とりあえず目についたのだけ書き換えたので全くもって不完全だが、Pythonを齧ったことある人なら方針は明快だと思う。
import kyotocabinet as kc class KyotoCabinet(kc.DB): def __del__(self): self.close() def open(self, *args, **kwds): if not super(KyotoCabinet, self).open(*args, **kwds): raise IOError("Open error: {0}".format(super(KyotoCabinet, self).error())) def set(self, *args, **kwds): if not super(KyotoCabinet, self).set(*args, **kwds): raise IOError("Set error: {0}".format(super(KyotoCabinet, self).error())) def close(self, *args, **kwds): if not super(KyotoCabinet, self).close(*args, **kwds): raise IOError("Close error: {0}".format(super(KyotoCabinet, self).error())) def cursor(self, *args, **kwds): cur = super(KyotoCabinet, self).cursor(*args, **kwds) cur.jump() while 1: rec = cur.get_str(True) if not rec: break yield rec cur.disable()
open, close, setが例外を投げるように、あとcursorをジェネレータ式に書き換えた。パフォーマンス的な問題は出るかもしれないが、あんなダサいのは見ていて耐えられない。
ぽんこつ式example
結果、あのかったるい例が
db = KyotoCabinet() db.open("sample.kch", kc.DB.OWRITER | kc.DB.OCREATE) db.set("1", "spam") db.set("2", "ham") db.set("3", "egg") print(db.get_str("2")) for rec in db.cursor(): print(rec[0], ":", rec[1])
こんなに短くなったよ!やったね!