先日の「C# CSVファイル、CSVリソースを配列化する関数」ですけどね。C#書くのは楽しめたけど、やっぱり「お気に入りのpyてょんと比べてどうも長ったらしいな」と、思ったわけよ。というわけで「1日1Python」の時間です。あっちと比べてホントに長ったらしいのか、実際にPythonで同じものを書いて試してみようじゃねーか。

あっちと同じ順番で書いてみる。

  1. 改行を含むCSVファイルを用意
  2. CSVをリソースに追加
  3. 今回作ったCSV二次元配列化関数
  4. 作った二次元配列を確認する関数を準備
  5. 実行
  6. 結果 (7. exe化)

1. 改行を含むCSVファイルを用意しとく

0,緑色,Midori-iro,"みどりいろ"
1,うぇる,Weruda,"ウェル
ダ"

これは前と同じ。

2. CSVをリソースに追加しとく

「リソースに追加する」ってのはC#だと「Visual Studioのリソース欄に追加する」って意味になるけど、そんなコトはpythonじゃできん。だけれど、CSVファイルをexeファイルに含めることはできないけれど、pyファイルをexeファイルに含めることは当然できることから、「CSVファイルの中身をpyファイルに埋め込んでpyファイルとしてプログラムに埋め込む」っつー手法を思いついた。以下のようなファイルを DEFAULT_CSV.py として準備。

# coding: utf-8
text = '''
0,緑色,Midori-iro,"みどりいろ"
1,うぇる,Weruda,"ウェル
ダ"
'''

3. 今回作ったCSV二次元配列化関数

import os,sys,csv,pprint
import DEFAULT_CSV       # デフォルトのCSVをこういう形でリソース化
from io import StringIO  # 後述。python2と3で読み込み方が違うトコ注意

# カレントディレクトリをプログラムのある場所、
# あるいはexeファイルの場所に移動する
def cd_():
    # cx_freezeで固めるとコレがTrueになる。
    if hasattr(sys, 'frozen'):
        os.chdir(os.path.dirname(sys.executable))
    else:
        os.chdir(os.path.dirname(os.path.abspath(__file__)))
cd_()

# 二次元配列化の関数
def foo(csv_path, default_csv_module):
    lis = []
    if os.path.isfile(csv_path):
        # しーえすぶい.csvがあればそれを使う
        print('しーえすぶい.csvを使います')
        with open(os.path.realpath(csv_path), 'r', encoding='UTF-8') as f:
            for row in csv.reader(f):
                lis.append(row)
    else:
        # ない場合はリソース(DEFAULT_CSV.py)を使う
        print('DEFAULT_CSV.pyを使います')
        for row in csv.reader(StringIO(default_csv_module.text.strip())):
            lis.append(row)
    return lis

カレントディレクトリ移動は「一石二鳥」とか「DialogFrame」あたりで学んだマイノウハウ。exe化するスクリプトには、なんとなくこれをつけておかないと不安になっちゃうだけで、本件にはあんまり関係ない。

StringIOモジュールは、手順2で用意した文字列をファイルオブジェクトに変換するのに必要。csv.reader()は文字列を直接扱ってはくれないようで、このワンクッションがいるみたい。

4. ついでに、作った二次元配列を確認する関数を準備

pprintを使うんで作る必要なし。pprintサンにはいつもお世話になってます。

5. 実行

# リソース用の引数にはモジュールをそのまま渡す
a = foo('しーえすぶい.csv', DEFAULT_CSV)
pprint.pprint(a)

6. 結果

オーケイだね。

7. exe化 ついでに今回のスクリプトのexe化に使ったcx_freeze設定を。以下のexe化ファイルを python cx_freeze.py build で実行。

# cx_freeze.py
import sys
from cx_Freeze import setup, Executable
exe = Executable(
    script = 'csv_read.py',
    # 出力が欲しいプログラムではbaseをNoneにするコト。
    base = None,
)
setup(
    name = 'CSVread',
    version = '0.1',
    executables = [exe],
)

8. 結論

長さでいえば当然、pythonに軍配が上がったかな。でもそれ以上に、CSV文字列を埋め込んだpyファイルをC#でいうところのリソースとして扱うっつー思いつきが面白かった。この我流感!