openpyxlでDefinedNameを使いこなす!変数のようにセル範囲を扱ってコードを綺麗にしよう

openpyxl

ws['G5'].value = subtotal ws['G6'].value = subtotal * tax_rate

このようなコードを書いたとき、「G5って何のセルだっけ?」と後から見返して分からなくなった経験はありませんか?セル番地を直接コードに書き込むと、その場は動いても、後々の修正や機能追加の際にコードの解読が非常に困難になります。

この問題を解決し、Pythonコードを劇的に綺麗にするための強力な機能が、Excelの「名前の定義」、openpyxlでいう**DefinedName**です。

この記事では、openpyxlDefinedName機能を使って、セル範囲に変数のような分かりやすい名前を付け、メンテナンス性の高いコードを書くための方法を解説します。

はじめに:なぜ「名前の定義」を使うべきなのか?

Excelでは、特定のセルや範囲に売上合計消費税率といったユニークな名前を付けることができます。これを「名前の定義」と呼びます。

この機能をopenpyxlから利用する最大のメリットは、コードの可読性が飛躍的に向上することです。ws['C10']と書く代わりにws['TAX_RATE']と書けるようになれば、そのセルが何を表しているのか一目瞭然です。まるでプログラミングの変数のように、Excelのセルを扱えるようになるのです。

グローバルな名前を定義する(ブック共通の変数)

グローバルな名前は、ブック内のどのシートからでも参照できる共通の名前です。消費税率や設定値など、ブック全体で共有したい固定値に名前を付けるのに最適です。

wb.defined_names.append()メソッドを使って簡単に作成できます。

import openpyxl
from openpyxl.workbook.defined_name import DefinedName

wb = openpyxl.Workbook()
ws = wb.active
ws.title = "設定シート"

# C2セルに消費税率を定義
ws['C2'].value = 0.1
ws['B2'].value = "消費税率"

# 'TAX_RATE' という名前を '設定シート'!$C$2 に割り当てる
# DefinedName(name="名前", attr_text="シート名!絶対参照セル")
new_name = DefinedName(name="TAX_RATE", attr_text="設定シート!$C$2")
wb.defined_names.append(new_name)

wb.save("defined_name_global.xlsx")

これで、このExcelファイルではTAX_RATE設定シートC2セルを指す「変数」のような存在になりました。

【応用】ローカルな名前を定義する(シート内だけの変数)

ローカルな名前は、特定のシート内だけで有効な名前です。例えば、複数の支店シートで、それぞれ小計セルにSUB_TOTALという同じ名前を付けたい場合に役立ちます。

DefinedNameオブジェクトを作成する際にlocalSheetId(シートのインデックス番号)を指定することで、名前の有効範囲をそのシートだけに限定できます。

import openpyxl
from openpyxl.workbook.defined_name import DefinedName

wb = openpyxl.Workbook()

# 東京支店シート (インデックス: 0)
ws_tokyo = wb.active
ws_tokyo.title = "東京支店"
ws_tokyo['E10'].value = 10000

# 大阪支店シート (インデックス: 1)
ws_osaka = wb.create_sheet("大阪支店")
ws_osaka['E15'].value = 8500

# 東京支店シートだけに有効な'SUB_TOTAL'を定義
name_tokyo = DefinedName(name="SUB_TOTAL", attr_text="東京支店!$E$10", localSheetId=0)
wb.defined_names.append(name_tokyo)

# 大阪支店シートだけに有効な'SUB_TOTAL'を定義
name_osaka = DefinedName(name="SUB_TOTAL", attr_text="大阪支店!$E$15", localSheetId=1)
wb.defined_names.append(name_osaka)

wb.save("defined_name_local.xlsx")

定義した名前を使ってセルにアクセスする

名前を定義したら、ws["名前"]という直感的な方法でセルにアクセスできます。これにより、コードから分かりにくいセル番地を追放できます。

Python

# グローバルの例で作成したファイルを開いて操作
wb_load = openpyxl.load_workbook("defined_name_global.xlsx")
ws_load = wb_load.active

# 'TAX_RATE'という名前を使ってC2セルにアクセス
tax_rate_cell = ws_load["TAX_RATE"]
print(f"名前でアクセスしたセルの値: {tax_rate_cell.value}")

# 変数のように値を更新
ws_load["TAX_RATE"].value = 0.08
print(f"更新後のC2セルの値: {ws_load['C2'].value}")

wb_load.save("defined_name_access.xlsx")

実行結果:

名前でアクセスしたセルの値: 0.1
更新後のC2セルの値: 0.08Code language: CSS (css)

コードの意図が明確になり、誰が読んでも理解しやすくなりました。

既存の名前定義を操作する

openpyxlでは、既存のファイルに含まれる名前定義を読み取ったり、削除したりすることも可能です。

  • 一覧取得: wb.defined_namesで定義済みオブジェクトにアクセスし、forループで内容を確認できます。
  • 削除: wb.defined_names.delete("名前")del wb.defined_names["名前"]で特定の名前を削除できます。(※バージョンにより挙動が異なる場合があります)

まとめ

今回は、openpyxlDefinedName機能を活用して、コードの可読性とメンテナンス性を劇的に向上させる方法を紹介しました。

  • DefinedNameを使うと、セル範囲に変数のような分かりやすい名前を付けられる
  • ブック全体で使える「グローバル名」と、シート固有の「ローカル名」を使い分けられる
  • 名前の作成はwb.defined_names.append()が基本
  • ws["名前"]でセルにアクセスすることで、セル番地のハードコーディングをなくせる

分かりにくいセル番地をコードから排除し、意味のある「名前」でExcelを操作する。この習慣が、あなたのPythonコードをより綺麗で、よりプロフェッショナルなものへと変えてくれるはずです。

コメント

タイトルとURLをコピーしました