Python学習チャンネル by PyQ

Pythonのオンライン学習プラットフォームPyQのオフィシャルブログです

Pythonお悩み解決【Pythonで正規表現を定数に分離する意味は?】

f:id:kenken0326:20191220155009p:plain

こんにちはPyQサポートです。 今回はPythonで定数に分離する意味を紹介します。

質問

SALES_FILE_REGEX = re.compile(r"sales_raw_(\d{4})(\d{2})(\d{2}).csv")

def main():
    sales = []
    for name in os.listdir("input/"):
        m = SALES_FILE_REGEX.search(name)

今回の SALES_RAW_REGEX売上⽣データのファイル名にマッチする正規表現という値です。
この正規表現はプログラム中も絶対に変わることがない固定の値です。
このように共通で使える固定の値を、Pythonファイルの上部に定数として書くことがあります。

PyQのクエスト「41-1: キレイなコードの書き方を学ぼう」4問目 の解説には上記のように記載されています。
ここで SALES_RAW_REGEXm = re.search(SALES_RAW_REGEX, name)にしか使われません。
そのため、直前に書かれるほうが読みやすいように感じます。

def main():
    sales = []
    for name in os.listdir("input/"):
        m = re.search(r"sales_raw_(\d{4})(\d{2})(\d{2}).csv", name)

定数を常にPythonファイルの上部に書くべきなのでしょうか?

回答

常にではありません。
ですが今回は SALES_FILE_REGEXP という正規表現を変数に分離することで、正規表現の意味を説明できる利点があります。

ご指摘のとおり定義の位置が離れてしまうと読みにくくなります。
その場合はプログラム自体を改善して、関数化やモジュールの分離をすると良いでしょう (その方法については、PyQ学習コンテンツ設計の後半で説明しています)。

定数に分離する意味

定数に分離することで、その定数の意味を説明できる利点があります。

今回は正規表現が、どんな意味を持つものなのかを説明できます。
正規表現は複雑なので見ただけでは理解しにくいでしょう。そのときに定数とすることで変数名そのものが意味を説明してくれます。

また今回のプログラムではもう1つ意味があります。
元のプログラムでは SALES_RAW_REGEX = re.compile(r"...正規表現") というように re.compile という処理を事前に行っています。
このre.compileは、Pythonが正規表現を解釈する処理を事前に行うという意味で、同じ正規表現を複数回実行するときにプログラムの高速化が期待できます(詳しくは後述します)。

re.compileは関数外で実行する必要があります。定数を分離するついでに以下のように関数の外に書くと良いでしょう。

SALES_RAW_REGEX = re.compile(r"...")

def main():
    ...
    SALES_RAW_REGEX.search(...)

また、Pythonは(条件によって)直前の正規表現をキャッシュするので、絶対的に re.compile する必要はありません。
速度、動作上問題なくプログラム的に読みにくくなるのであれば、無理に定数して re.compile を使わなくても問題ありません。

re.compile() やモジュールレベルのマッチング関数に渡された最新のパターンはコンパイル済みのものがキャッシュされるので、一度に正規表現を少ししか使わないプログラムでは正規表現をコンパイルする必要はありません。 re --- 正規表現操作 — Python 3.8.1 ドキュメント

プログラムの可読性をあげたり意味を説明する方法はコメントだけではありません。
関数化、モジュールの分割、今回のような定数化によって意図を説明することで、プログラムの可読性をあげましょう。

Copyright ©2017-2020 BeProud Inc. All rights reserved.