前書き
今回取り扱う内容は、『Pythonに退屈なことをやらせよう』という本の内容に書かれているプログラムを取り扱いますが、本の内容はあまり重要ではありません。今回学ぶことは(学んだことは)pythonプログラムを使って膨大なエクセルデータから品物の価格を更新することです。
それと今回の内容とあまり関係はありませんが「pythonのopenpyxlモジュールを使ってエクセル操作」はシリーズ化してありますので下記サイトも参考にしてください
- pythonのopenpyxlモジュールを使ってエクセル操作【1時間目:準備】
- pythonのopenpyxlモジュールを使ってエクセル操作【2時間目:シートの取得】
- pythonのopenpyxlモジュールを使ってエクセル操作【3時間目:セル操作】
- pythonのopenpyxlモジュールを使ってエクセル操作【4時間目:もっとセル操作】
使用するデータ
まずはここから膨大な価格情報が書かれているエクセルファイルをダウンロードしてください。
automatestuff-ja/produceSales.xlsx at master · oreilly-japan/automatestuff-ja · GitHub
このエクセルファイルには品物の名前と値段と重さと総価格が書かれています。
もしこんなふうに品物とその価格情報をひとつの膨大なエクセルファイルとして管理していた場合、ある項目を更新するのは非常に時間がかかってしまう作業になるかもしれません。
たとえ「Garlic」「Celery」「Lemon」の価格を更新したい場合、まず商品名を探すのに時間がかかると思います。これに関してはエクセルの関数などを使えば簡単にできるかもしれませんが、今回はpythonのプログラムを使って品物の価格情報を更新します。
pythonのコードで品物の価格を更新する
今回はpythonのコードで価格更新をします。これは、ひょっとすると役に立つ人には奴に立つかもしれないです。それではコードを見ていきましょう。
import openpyxl wb = openpyxl.load_workbook('produceSales.xlsx') sheet = wb.get_sheet_by_name('Sheet') # 農産物の種類と、更新する価格 PRICE_UPDATE = { 'Garlic': 3.87, 'Celery': 1.19, 'Lemon': 1.27 } # 行をループして価格を更新する。 for row_num in range(2, sheet.max_row): # 先頭の行を飛ばして全ての行をループ produce_name = sheet.cell(row=row_num, column=1).value # produce_nameにはセルの値が if produce_name in PRICE_UPDATE: # セルの値がキーとして存在したら sheet.cell(row=row_num, column=2).value = PRICE_UPDATE[produce_name] # キーが存在したときはprice_updateの値を代入 wb.save('updatedProduceSales.xlsx')
今回はわりとシンプルなコードになっています。品物の列をforループで全ての行を検索します。問題は13行目です。これは「セルの値がキーとして存在したら」という意味になります。その条件のときだけ14行目を実行します。
14行目は少し難しいかもしれません。PRICE_UPDATE[キー名]とすることで→その値(Garlicだったら3.87)がシートのセルに書き換わることになります。
どうでしょう?これは結構すごい?ような気がします。
forループは実際にどんなふうに回っているかイメージしにくいかもしれません。produce_name変数がありますが、これは一気に代入されているというわけではなく、シートの1行1行順番に値が代入されていると考えれば少し理解しやすいかもしれません。
実際にspyderのデバッグ機能のstep実行を使って1行ずつプログラムをすすめてみればわかります。
余談:プログラム実行中にエクセルファイルを操作するとブルースクリーンが発生した
Pythonプログラムを実行中にエクセルファイルを操作する際は、バグが発生してWindowsでブルースクリーンになる可能性があることをご留意ください。
さらに、このプログラムの最後の16行目で、新しい名前でエクセルファイルを保存していることがわかります。.save()メソッドに元のファイル名を渡すと上書きされますが、バグのリスクを考慮すると、新しいファイル名で保存したほうがよいかもしれません。
コメント