done is better than perfect

自分が学んだことや、作成したプログラムの記事を書きます。すべての記載は他に定める場合を除き個人的なものです。

Python(2系列)とsqlite3でハマった話

Python 2.7.3 + sqlite3で少しハマりました。

col_nameというカラム名を持つtableが存在するsqliteのデータベースファイルsqlite.dbがあるとして、以下の様なコードを書くとエラーになります。

from __future__ import unicode_literals
import sqlite3

con = sqlite3.connect("./sqlite.db")
con.row_factory = sqlite3.Row
cur = con.cursor()

cur.execute("SELECT * FROM tbl_name")
cur.fetchall()["col_name"]

エラーコード

...
IndexError: Index must be int or string

怒られている理由は検討つきます。未来からunicode_literalsを持ってきたせいで、keyとしてunicode文字列は使えないのでしょう。 実際に、以下のコードはエラーなく期待した動作をします。

cur.fetchall()["col_name".encode("utf-8")]

いちいちアクセスするたびにencodeを呼び出していたら、なんのためにunicode_literalsを呼び出したのかわかりません。

結果として悪さをしていたのは

con.row_factory = sqlite3.Row

これを、Pythonの公式Docに従って、dict_factory関数を使うことによって解決出来ました。

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

...
con.row_factory = dict_factory

エラーをググっても情報が出てこなくて焦りました。やっぱりまず公式リファレンスを見たほうがいいですね。