PythonでExcelを上手に読む

PythonでExcelを読むには、http://pypi.python.org/pypi/pyExceleratorhttp://pypi.python.org/pypi/xlwtを使うんですが、このpyExceleratorのパース結果が、Excel向きのメソッドのあるオブジェクトじゃなくて、リストとタプルと辞書だけでできていたりして、きれいなんだけど、逆にOOPなPGには扱いにくかったりします。

[
  ('Sheet1', {(0,0):1, (1,0):2, (2,0):3, (1,0):4, ... }),
  ('Sheet2', { ... }),
  ...
]

こんな感じ。

手続き主体の人が何も考えずに書くと、こんなプログラムになるんじゃないかなと思うサンプル。

import pyExcelerator

# シート名をキーにした辞書にデータを入れた book を作る
sheets = pyExcelerator.parse_xls("test.xls")
book = dict()
for name,sheet in sheets:
    book[name] = sheet

# Sheet1を取り出して sheet1 に格納。該当なければ空
if 'Sheet1' in book.keys():
    sheet1 = book['Sheet1']
else:
    sheet1 = {(0,0):0}

# 列と行の最大を得る
maxcols = 0
maxrows = 0
for col,row in sheet1.keys():
    if col > maxcols: maxcols = col
    if row > maxrows: maxrows = row

# 行、列でループ
for i in range(maxrows + 1):
    for j in range(maxcols + 1):
        if sheet1.has_key((i, j)):
            print "[%d,%d] = %s" % (i, j, sheet1[(i,j)])
        else:
            print "[%d,%d] = %s" % (i, j, None)

ああ面倒。でも、上手に書くと、こんな感じ。

import pyExcelerator

book = dict(pyExcelerator.parse_xls("test.xls")) # 本
sheet1 = book.get('Sheet1', {(0,0):0})           # シート
maxcols,maxrows = map(max, zip(*sheet1.keys()))  # 最大列/行

# ループ
for i in range(maxrows + 1):
    for j in range(maxcols + 1):
        print "[%d,%d] = %s" % (i, j, sheet1.get((i,j), None))

dict関数は、実は、[(key, value), (key, value), ...]のようなシーケンスから辞書を作れるんですね。

で、辞書オブジェクトはあえてgetメソッドを使うことで、キーがないというエラーにならず、しかも、キーがなかったときのデフォルト値を指定できる。

あと、zip関数をうまく使うと、

zip((1,2,3), (4,5,6)) # キーリスト、バリューリスト
# => ((1,4), (2,5), (3,6)) キーバリューペア

zip((1,2), (3,4), (5,6)) # キーバリューペア
# => ((1,3,5),(2,4,6)) キーリスト、バリューリスト

こんな感じで転置できるので、(列,行)という形式のキーリストからワンライナーで最大列と最大行が得られます。

これで、Excelを直で読むプログラムがさっさと書き始められます。