読者です 読者をやめる 読者になる 読者になる

ざっくりん雑記

プログラミングで忘れそうなことをひたすらメモる

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」を消した。

余談だが、ムーミン谷のリトルミイの名言の一つにこの言葉がある。

f:id:azuuun:20150509121614j:plain

何とかなる。それは、やることをちゃんとやってる人のセリフ。

"""そもそもワンチャンはちゃんと努力した人に訪れるのだ"""

だから、軽はずみに"ワンチャンあるっしょ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__にモジュール名が代入される

言い換えると、

「 if name == 'main': 」ステートメント

  • コマンドラインでファイルを指定して起動された場合は True で実行される
  • importでインポートされた場合は False で実行されない

ということ。

どう応用する?

たとえば、

「モジュールを作っているとき、かんたんにテストしたい(値をprintするなどで確認する)コードを書くとき」

これは、他のモジュールにインポートされた時には表示する必要がなかったりする。

そういう時は、テストするためのコードを「if __name__ == '__main__':」の中にかけば、 トップレベルファイルで実行された時にのみ、テスト用の値出力処理が行われるようにすることができる。

他のモジュールからインポートされた時は False となり、実行されない。ちょっと便利。

この他にも使いドコロがありそう!

まとめると

「直接実行されているのか、それともimportされて実行されているのかが、この__name__変数の値を確認することで分かる!」