if __name__ == "__main__": は何をするのでしょうか?

if name == "main":` は何をするのでしょうか?

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

if __name__ == "__main__":
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))
ソリューション

Pythonインタープリタがソースファイルを読み込むときには、必ず2つのことを行います。

  • __name__ のようないくつかの特別な変数を設定し、次に

  • そのファイルに含まれるすべてのコードを実行します。

この仕組みと、Pythonスクリプトでいつも見られる__name__のチェックについての質問との関連を見てみましょう。

コードサンプル

インポートとスクリプトがどのように機能するかを調べるために、少し異なるコードサンプルを使ってみましょう。 以下の内容が foo.py というファイルの中にあるとします。

# Suppose this is foo.py.

print("before import")
import math

print("before functionA")
def functionA():
    print("Function A")

print("before functionB")
def functionB():
    print("Function B {}".format(math.sqrt(100)))

print("before __name__ guard")
if __name__ == '__main__':
    functionA()
    functionB()
print("after __name__ guard")

特別な変数

Python interpeterがソースファイルを読み込むときには、まずいくつかの特殊変数を定義します。ここでは、__name__という変数について説明します。

あなたのモジュールがメインプログラムの場合

モジュール(ソースファイル)をメインプログラムとして実行している場合、例えば以下のようになります。

python foo.py

インタープリタは、ハードコードされた文字列 "__main__"__name__ 変数に代入します、つまり

# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__" 

自分のモジュールが他のモジュールにインポートされたとき

一方で、他のモジュールがメインプログラムで、あなたのモジュールをインポートしているとします。これは、メインプログラムの中に、あるいはメインプログラムがインポートしている他のモジュールの中に、このような文があるということです。

# Suppose this is in some other main program.
import foo

この場合、インタプリタはあなたのモジュールのファイル名である foo.py を見て、.py を取り除き、その文字列をあなたのモジュールの __name__ 変数に代入します、つまり

# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"

モジュールのコードを実行する

特殊変数の設定が終わると、インタプリタはモジュールの全コードを1文ずつ実行します。コードサンプルが表示されている側に別のウィンドウを開いて、この説明を追えるようにしておくとよいでしょう。

常に

1.文字列 "before import"(引用符なし)を表示します。

2.2. math モジュールをロードして math という変数に代入します。これは、import math を以下のように置き換えることと同じです(__import__ は Python の低レベル関数で、文字列を受け取って実際のインポートを実行することに注意してください)。

# "math "という文字列名のモジュールを探してロードします。
# そして、それを math というローカル変数に割り当てます。
math = __import__("math")

3.文字列 "before functionA" を表示します。

4.defブロックを実行して、関数オブジェクトを作成し、その関数オブジェクトをfunctionA`という変数に代入します。

5.文字列 "before functionB" を表示します。

6.6. 2番目の def ブロックが実行され、別の関数オブジェクトが作成され、それが functionB という変数に代入されます。

7.文字列 "before __name__ guard" を表示します。

あなたのモジュールがメインプログラムの場合のみ

8.あなたのモジュールがメインプログラムの場合、__name__ が確かに "__main__" に設定されていることを確認し、2つの関数を呼び出して、文字列 "Function A""Function B 10.0" を表示しています。

あなたのモジュールが他のモジュールからインポートされたときのみ

8.(instead) あなたのモジュールがメインプログラムではなく、他のモジュールにインポートされていた場合、__name__"__main__" ではなく "foo" となり、if 文の本文はスキップされます。

常に

9.どちらの状況でも "after __name__ guard" という文字列が表示されます。

まとめ

要約すると、2つのケースで何が表示されるかを示します。

# What gets printed if foo is the main program
before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard
# What gets printed if foo is imported as a regular module
before import
before functionA
before functionB
before __name__ guard
after __name__ guard

なぜこのような仕組みになっているのか?

なぜこんなことをしたいのかと思うかもしれません。 さて、.py ファイルを書いて、他のプログラムやモジュールからモジュールとして利用したり、メインプログラムとして実行したりしたい場合があります。 例を挙げてみましょう。

  • あなたのモジュールはライブラリですが、ユニットテストやデモを実行するスクリプトモードを持ちたいとします。

  • あなたのモジュールは、メインプログラムとしてのみ使用されますが、いくつかのユニットテストを持っており、テストフレームワークは、あなたのスクリプトのような .py ファイルをインポートし、特別なテスト関数を実行することで動作します。モジュールをインポートしているからといって、スクリプトを実行しようとはしないでほしいのです。

  • あなたのモジュールは、主にメインプログラムとして使用されますが、上級ユーザーのためにプログラマーフレンドリーなAPIも提供しています。

これらの例に限らず、Pythonでスクリプトを実行することは、いくつかの魔法の変数を設定し、スクリプトをインポートするだけであることはエレガントです。スクリプトの "実行 "は、スクリプトのモジュールをインポートすることによる副次的な効果です。

Food for Thought

  • 質問です。複数の __name__ チェックブロックを持つことはできますか? 答え:そうするのはおかしいですが、言語はあなたを止めません。

  • 次のようなものが foo2.py にあるとします。 コマンドラインで python foo2.py と言ったらどうなりますか?なぜですか?

# Suppose this is foo2.py.

def functionA():
    print("a1")
    from foo2 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    functionA()
    print("m2")
print("t2")
  • さて、foo3.py__name__ のチェックを外したらどうなるか考えてみましょう。
# Suppose this is foo3.py.

def functionA():
    print("a1")
    from foo3 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
print("m1")
functionA()
print("m2")
print("t2")
  • スクリプトとして使われるとき、これは何をしますか? モジュールとしてインポートすると?
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")

print("before __name__ guard")
if __name__ == "__main__":
    bar()
print("after __name__ guard")
解説 (6)

スクリプトをPythonインタープリターにコマンドとして渡して実行する場合。

python myscript.py

インデントレベル 0 のコードはすべて実行されます。 定義されている関数やクラスは、まあ、定義されていますが、そのコードは何も実行されません。 他の言語と違って、自動的に実行されるmain()関数はありません。main()関数は暗黙のうちにトップレベルのすべてのコードです。

この場合、トップレベルのコードとは if ブロックのことです。 nameは組み込み変数で、現在のモジュールの名前として評価されます。 しかし、モジュールが直接実行されている場合(上記のmyscript.pyのように)、代わりにnameには文字列"main"` が設定されます。 したがって、スクリプトが直接実行されているのか、何か他のものからインポートされているのかをテストするには、次のようにします。

if __name__ == "__main__":
    ...

スクリプトが他のモジュールにインポートされている場合、その様々な関数やクラスの定義がインポートされ、トップレベルのコードが実行されますが、上記の if 節の then-body にあるコードは、条件が満たされていないため実行されません。基本的な例として、次の2つのスクリプトを考えてみましょう。

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

さて、インタプリタを次のように起動すると

python one.py

という出力が得られます。

top-level in one.py
one.py is being run directly

代わりに two.py を実行した場合。

python two.py

次のようになります。

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

このように、モジュール one がロードされると、その __name__"main__" ではなく "one" になります。

解説 (0)

if name == "main"は、スクリプトがコマンドラインからpython myscript.py` のようなコマンドを使って実行されたときに実行される部分です。

解説 (1)