Python - if __name__ == '__main__': の意味
if __name__ == '__main__':
って何?
サンプルコードにも頻出するこの__name__
属性。
Pythonを勉強し始めて3日ぐらいのときに一度調べたのだけど「???」な感じだった。
で、きょう今一度調べてみるとやっと理解できた。
Pythonを始めて3日目の自分でも理解できるようにやたら冗長に説明するメモを残したいと思う。(しつこいくらいに同じこと言ってる)
例えば test.py というスクリプトを書いたとする。
#!/usr/bin/env python # -*- coding: utf-8 -*- def shout(): print u"ウェーイw" print u"ワンチャンあるっしょw" if __name__ == '__main__': shout()
ウェーイ系のセリフを2つ用意した。
基本的に、print文「ワンチャンあるっしょw」は絶対実行される。
print文「ウェーイw」は 「 if __name__ == '__main__':
」が True である場合のみ、def文の shout() が実行され「ウェーイw」する。
コマンドラインから上記の test.py を指定してPythonインタプリタを起動する。(実行する)
> python test.py
結果はこうなる。
>test.py ワンチャンあるっしょw ウェーイw
結果から、
「 if __name__ == '__main__':
」の判定は True となって、shout関数が呼び出され、いわゆるウェーイ系大学生が「ウェーイw」したことが分かる。
え、なんで「 if __name__ == '__main__':
」がTrueになってるの?
__name__
という変数を作った覚えも、
__name__
に__main__
なんて代入した覚えないよ?って思うよね。(Python始めて3日目の自分はそう思った)
まず、__name__
属性についての説明をじっくり読んで欲しい。
コマンドラインからスクリプトファイルを指定してPythonインタプリタを起動すると、指定されたファイルは、
__main__
という名前のモジュールとしてPythonに読み込まれる。実行中スクリプトのモジュールの名前は、__name__
という名前の変数に設定されているため、この値を参照して、ファイルがコマンドラインから実行されたのか、それともimport文でインポートされたのかを識別できる。
という仕組みになっているようだ。
つまり、コマンドラインから直接スクリプトファイルを実行した場合は「__name__
という変数(属性)の中に自動的に__main__
を代入する」操作が一番はじめに水面下で行われる。
だから、test.py の場合の判定は True になった。
逆に、コマンドラインから直接スクリプトファイルを実行しない場合って何?って感じなんだけど、それはimport文でスクリプトファイルがモジュールとしてインポートされた場合。
import で読み込まれたスクリプトファイルの場合は そのモジュール名 が__name__
に入る。
例えば test.py をモジュールとしてimportして実行した場合は __name__
には test が入る。
実際に test.py がimportでインポートした場合を試してみる。
test.py の内容を少し変える。
#!/usr/bin/env python # -*- coding: utf-8 -*- print __name__ def shout(): print u"ウェーイw" if __name__ == '__main__': shout()
初めに __name__
の中身をprintするようにし、「ワンチャンあるっしょw」を消した。
余談だが、ムーミン谷のリトルミイの名言の一つにこの言葉がある。
何とかなる。それは、やることをちゃんとやってる人のセリフ。
"""そもそもワンチャンはちゃんと努力した人に訪れるのだ"""
だから、軽はずみに"ワンチャンあるっしょw"とか言わないようにしたい。
話を戻す。
まずは、
__main__ ウェーイw
実行時に __name__
には __main__
が入っていて、コマンドラインから直接スクリプトファイルが実行されたことがわかるし、「if __name__ == '__main__':
」判定が True となって「ウェーイw」したことも分かる。
- test.pyをimportしたtest_import.pyを実行した場合
test_import.pyの中身
#!/usr/bin/env python # -*- coding: utf-8 -*- import test
実行する
test
testとしか出力されない。
つまり、importした場合は__name__
にはモジュール名、今回の場合は
test が入り、のちのif判定もFalseとなり、shout関数も実行されず「ウェーイw」しなかった。
つまり?
__name__
属性は、
- モジュール作成と同時に自動的に与えられて以下の設定が行われる
- モジュールファイルがトップレベルファイル(main)として機能する ==>
__name__に__main__
が代入される - モジュールファイルがインポートされる ==>
__name__
にモジュール名が代入される
- モジュールファイルがトップレベルファイル(main)として機能する ==>
言い換えると、
「 if name == 'main': 」ステートメントは
- コマンドラインでファイルを指定して起動された場合は True で実行される
- importでインポートされた場合は False で実行されない
ということ。
どう応用する?
たとえば、
「モジュールを作っているとき、かんたんにテストしたい(値をprintするなどで確認する)コードを書くとき」
これは、他のモジュールにインポートされた時には表示する必要がなかったりする。
そういう時は、テストするためのコードを「if __name__ == '__main__':
」の中にかけば、
トップレベルファイルで実行された時にのみ、テスト用の値出力処理が行われるようにすることができる。
他のモジュールからインポートされた時は False となり、実行されない。ちょっと便利。
この他にも使いドコロがありそう!
まとめると
「直接実行されているのか、それともimportされて実行されているのかが、この__name__
変数の値を確認することで分かる!」