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でスクリプトを実行することは、いくつかの魔法の変数を設定し、スクリプトをインポートするだけであることはエレガントです。スクリプトの "実行 "は、スクリプトのモジュールをインポートすることによる副次的な効果です。
質問です。複数の __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")
スクリプトを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"
になります。
if name == "main"は、スクリプトがコマンドラインから
python myscript.py` のようなコマンドを使って実行されたときに実行される部分です。