note.nkmk.me

Pythonのif __name__ == '__main__'の意味と使い方

Date: 2018-07-29 / tags: Python

Python初心者がサンプルコードを見たときに理解に苦しむのが、おまじないのように書かれているif __name__ == '__main__'

アンダースコアに惑わされてしまうが「__name__に格納されている値が'__main__'という文字列である場合に以降の処理を実行する」という単なるif文なので、__name__'__main__'の意味が分かれば理解しやすい。

以下の内容について説明する。

  • __name__とは
  • '__main__'とは
  • if __name__ == '__main__'の意味
  • if __name__ == '__main__'の使い方、使いどころ
    • モジュールのテストコードを記述
    • モジュールをコマンドとして利用
  • Pythonにおけるmain()関数

なお、Pythonでは文字列リテラルをシングルクォート'でもダブルクォート"でも表せるので、if __name__ == "__main__"でも同じ意味。

スポンサーリンク

__name__とは

モジュールをインポートするとその__name__属性にモジュールの名前が文字列として格納される。<モジュール名>.__name__で取得できる。

import math
import numpy as np

print(math.__name__)
# math

print(np.__name__)
# numpy

自作のモジュールでも同じ。例として以下のようなモジュールhellohello.py)を作成する。モジュール内で__name__を出力する関数を定義している。

def func():
    print('Hello!')
    print('__name__ is', __name__)
source: hello.py

このモジュールhelloをインポートして使うと以下のようになる。

import hello

print(hello.__name__)
# hello

hello.func()
# Hello!
# __name__ is hello

インポートされたモジュールの__name__にはモジュール名'hello'が格納されていることが分かる。

'__main__'とは

上述のように、別のファイルからインポートされると__name__にはモジュール名が格納される。

一方、ファイルをコマンドラインからスクリプトとして実行すると__name__には'__main__'という文字列が格納される。

例としてtest_moduleというモジュール(test_module.py)とそれをインポートして使うtest_main.pyを作成する。

def func():
    print('    This is func() in test_module.py')
    print('    __name__ is', __name__)

if __name__ == '__main__':
    print("Start if __name__ == '__main__'")
    print('call func()')
    func()
import test_module

print('This is test_main.py')
print('test_module.__name__ is', test_module.__name__)

print('---')
print('call test_module.func()')

test_module.func()
source: test_main.py

test_main.pyをコマンドラインからpython(またはpython3)コマンドで実行すると以下のような結果となる。

python3 test_main.py
# This is test_main.py
# test_module.__name__ is test_module
# ---
# call test_module.func()
#     This is func() in test_module.py
#     __name__ is test_module

helloの例と同様に、インポートされたモジュールtest_module__name__にはモジュール名'test_module'が格納されている。

一方、test_module.py自体をコマンドラインから実行すると以下のような結果となる。

python3 test_module.py
# Start if __name__ == '__main__'
# call func()
#     This is func() in test_module.py
#     __name__ is __main__

__name__には'__main__'という文字列が格納され、if __name__ == '__main__':以降の処理が実行されていることが分かる。

このように、他のファイルからインポートされた場合は__name__'<モジュール名>'が格納され、コマンドラインからpython(またはpython3)コマンドで実行された場合は__name__'__main__'という文字列が格納される。

なお、pythonコマンドに-mオプションをつけてモジュールとして実行する場合やインタラクティブモードでも__name__には'__main__'という文字列が格納される。

python3 -m test_module
# Start if __name__ == '__main__'
# call func()
#     This is func() in test_module.py
#     __name__ is __main__

if __name__ == '__main__'の意味

まとめると、__name__に格納される値は以下の通り。

  • 他のファイルからインポートされたとき
    • __name__'<モジュール名>'
  • そのファイル自体がpython(またはpython3)コマンドでスクリプトとして実行されたとき
    • __name__'__main__'

したがって、if __name__ == '__main__'は「該当のファイルがコマンドラインからスクリプトとして実行された場合にのみ以降の処理を実行する」という意味となる。他のファイルからインポートされたときは処理は実行されない。

if __name__ == '__main__'の使い方、使いどころ

if __name__ == '__main__'を使うと、モジュールのテストコードを記述したり、モジュールをコマンドとして利用できるようにしたりすることが可能。

モジュールのテストコードを記述

モジュールの関数の出力結果を確認したいというような場合に、if __name__ == '__main__'以下にテストコードを書いておく。

例えば上述のhello.pyの場合。

def func():
    print('Hello!')
    print('__name__ is', __name__)
source: hello.py

関数が定義されているだけなので、このファイルをコマンドラインから実行してもなにも起こらない。

python3 hello.py

if __name__ == '__main__'を追加する。

def func():
    print('Hello!')
    print('__name__ is', __name__)

if __name__ == '__main__':
    func()

これをコマンドラインから実行すると、if __name__ == '__main__'以下のコードに従ってモジュール内の関数が実行される。

python3 hello_if_name.py
# Hello!
# __name__ is __main__

他のファイルからインポートされた場合はif __name__ == '__main__'以下のコードは実行されないので、余計な処理が発生することはない。

モジュールをコマンドとして利用

モジュールをコマンドとして利用したい場合にもif __name__ == '__main__'が使える。

以下のようなモジュールを作成する。

import sys

def add(a, b):
    return a + b


if __name__ == '__main__':
    print(add(float(sys.argv[1]), float(sys.argv[2])))

if __name__ == '__main__'以下ではsys.argvでコマンドライン引数を取得しモジュール内の関数に渡している。

sys.argvはコマンドライン引数のリストで最初の要素sys.argv[0]はスクリプト名となる。また、文字列として格納されるので数値として扱いたい場合はint(), float()などで変換する。

これによって、コマンドラインから引数をつけて実行した場合、モジュール内の関数が処理される。

python3 add_module.py 1.2 3.4
# 4.6

他のファイルからインポートして使うことももちろん可能。この場合はif __name__ == '__main__'以下のコードは実行されない。

import add_module

print(add_module.add(100, 200))
# 300

なお、モジュールをコマンドとして使いたい場合は、そのためのファイルを別途用意してもOK。

import sys
import add_module

print(add_module.add(float(sys.argv[1]), float(sys.argv[2])))

これを実行した結果は以下の通り。

python3 add_module_command.py 1.2 3.4
# 4.6

この場合、if __name__ == '__main__'は必要ない。

特にargparseモジュールなどを使ってコマンド化する場合は別のファイルにしたほうがスッキリする。

import argparse
import add_module

parser = argparse.ArgumentParser()
parser.add_argument('a', type=float)
parser.add_argument('b', type=float)

args = parser.parse_args()
print(add_module.add(args.a, args.b))

これを実行した結果は以下の通り。

python3 add_module_argparse.py 1.2 3.4
# 4.6

Pythonにおけるmain()関数

ついでにPythonにおけるmain()関数にも触れておく。

PythonではC言語のようにmain()関数から処理が実行されるというわけではなく、mainという名前の関数を定義したからといって自動的にその関数から処理が始まるわけではない。

以下の2つのコードはどちらも同じ実行結果となる。

main()関数を記述。

def main():
    print('Hello!')

if __name__ == '__main__':
    main()

処理を直接記述。

print('Hello!')

コマンドラインから実行したときの結果は同じ。

python3 hello_main.py
# Hello!

python3 hello_direct.py
# Hello!

特に大規模なプログラムの場合は慣例として起点となる関数をmain()という名前にしておくことが多いが、これはあくまでも分かりやすさのためで、仕様として特別な意味はないし、必須でもない。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事