python + sqlite3でリストを簡単に扱う


sqlite3にはリスト型は存在しないため、例えばintegerのリストを格納したい場合はstr()して;(セミコロン)区切りの文字列にjoin()して格納、取り出すときはsplit()してint()するという操作が必要となる。

sqlite3モジュールにはこれらの操作を予め登録し必要に応じて自動で実行する仕組みが存在している。

これによりリスト要素の型が全て一致していることがわかっているのであれば、変換関数をregister_adapter()register_converter()を使って登録することでリストをシームレスに扱うことができる。

以下の例ではtesttableにIntListという型を定義してregister_adapter()register_converter()を使いpythonのデータ型との変換方法を登録している。
connectするときのdetect_types = sqlite3.PARSE_DECLTYPESは必須。

test.py
import sqlite3

CREATE_TABLE = u"""
create table if not exists testtable (
  id      integer primary key,
  intlist IntList
);
"""

IntList = list
sqlite3.register_adapter(IntList, lambda l: ';'.join([str(i) for i in l]))
sqlite3.register_converter("IntList", lambda s: [int(i) for i in s.split(';')])

def main():
    con = sqlite3.connect(":memory:", detect_types = sqlite3.PARSE_DECLTYPES)
    con.row_factory = sqlite3.Row
    con.execute(CREATE_TABLE)

    insert_list = [1,2,3]
    con.execute(u'insert into testtable values(?, ?)', (1, insert_list))
    con.commit()

    cur = con.cursor()
    cur.execute(u'select * from testtable;')
    assert insert_list == cur.fetchone()['intlist']

if __name__ == '__main__':
    main()

register_adapter()register_converter()はユーザ定義の型でももちろん利用可能。
参考: http://docs.python.jp/2/library/sqlite3.html#id6