Python Tips: Python で main 関数を定義することのメリット

今回は Python のスクリプトにおいてエントリーポイントとなる main 関数を定義することのメリットについて説明します。

# わざわざ main 関数を定義してその中に処理を書く
def main():
    ...


if __name__ == "__main__":
    main()

Python では本来 main 関数を定義する必要はありませんが、経験者が書いたスクリプトではよく main 関数が書かれています。 筆者は Python を学び始めた頃にそのようなコードを見て「必要ないものをなぜわざわざ書くのだろう?」と疑問に思いました。 今回は筆者自身がかつて抱いたこの疑問に答えてみます。

尚、 main という名前を使うのはただの慣習です。 この名前の関数にしないといけない制約は特にありません。

本記事において、「 main 関数を定義する」というのは、正確には上のコードのように main 関数を定義した上で、ファイル末尾に if __name__ == "__main__": を書いてそこで main 関数を呼び出すことを意味しますが、ここではかんたんに「 main 関数を定義する」と表現します。

Python で main 関数を定義することのメリット

Python スクリプトで main 関数を定義することにはさまざまなメリットがあります。

  1. 関数の定義を後ろに書ける
  2. 抽象度の高い処理の流れを main 関数で示せる
  3. 処理の変更や差し替えがしやすい
  4. テストが書きやすい
  5. 変数名の意図しない衝突を防げる

1. 関数の定義を後ろに書ける

JavaScript で起こるようなスコープ内の関数名の巻き上げが Python では起こらないため、関数は定義した後でしか使うことができません。

# 関数は定義よりも前で使うことができないので、このコードを実行するとエラーになる
func_a()
# => NameError: name 'func_a' is not defined


def func_a():
    ...

main 関数を使うことで、 main 内で使う関数の定義を利用場所の後に書くことができます。

# エラーなく `func_a()` が実行できる
def main():
    func_a()


def func_a():
    ...


if __name__ == "__main__":
    main()

2. 抽象度の高い処理の流れを main 関数で示せる

1 の「関数の定義を後ろに書ける」とも関係しますが、 main 関数を導入する( & 処理を関数に分ける)ことで、抽象度の高いコードと詳細のコードを分けることができます。

おおまかな処理の流れを main 関数に、詳細を各関数に分けることで、全体の見通しがよくなります。 たとえば次のようなコードであれば、 main 関数を見るだけでどのような処理が行われているのかを大まかに把握することができます。

def main():
    # ここを読めば、データの読み込み → 処理 → 結果の保存 をしていることはわかる
    data = load_data()
    result = process_data(data)
    save_data(result)


def load_data():
    ...


def process_data(data):
    ...


def save_data(result):
    ...


if __name__ == "__main__":
    main()

3. 処理の変更や差し替えがしやすい

main 関数を使わずコードをベタ書きしていると、処理の変更や一時的な差し替えが必要な場合に、多くの行を書き換えなくてはなりません。

main 関数を定義しておくと、たとえば処理の大部分を変更する必要がある場合には、既存の main 関数を main_old 等にリネームして新たな main 関数を定義するといったことをすれば大幅な変更でもすばやく対応できます。

4. テストが書きやすい

main 関数を使わずコードをベタ書きしていると自動テストが書きづらくなります。

5. 変数名の意図しない衝突を防げる

main 関数を使わずコードをベタ書きすると、多くの変数がグローバル変数のような扱いになってしまいます。 結果として、意図しない変数名の重複によるバグの発生や、用済みデータが残ることによる無駄なメモリの使用等が起こりえます。

# 意図しない変数名の重複の例
result = fetch_data()

...

# `calculate()` の結果を表示するための `print()` を追加したが
# 間違えて `calculate()` の前に `print()` を書いてしまった
# ↓
# 本来 `NameError` が起こってすぐに気づくはずだが
# 変数 `result` を上でも使っているのでエラーにならず間違いの発見が遅れる
print(result)
result = calculate()

……このぐらいでしょうか。 細かくあげていくと他にもあげられそうな気がします。

ということで、 Python スクリプトにおいて main 関数を書くことのメリットについてでした。