これは何をするものですか、そしてなぜこのif
声明を含める必要があるのですか?
if __name__ == "__main__":
print("Hello, World!")
誰かがこの慣用句を使うべきなのに使っていない質問をクローズしようとしている場合は、重複としてクローズすることを検討してください。モジュールをインポートすると Python が実行するのはなぜですか? また、それを停止するにはどうすればよいですか?代わりに、関数をまったく呼び出していない、または関数名がmain
エントリポイントとして自動的に使用されると誤って想定している質問の場合は、Python スクリプトを開始しても main() 関数が実行されないのはなぜですか? スクリプトはどこから実行を開始しますか?。
ベストアンサー1
短い答え
これは、ユーザーが意図せずに誤ってスクリプトを呼び出すのを防ぐ定型コードです。スクリプトからガードが省略された場合によく発生する問題は次のとおりです。
ガードレス スクリプトを別のスクリプト (例 ) にインポートすると、後者のスクリプトはインポート時に
import my_script_without_a_name_eq_main_guard
前者のスクリプトの実行をトリガーし、2 番目のスクリプトのコマンド ライン引数を使用します。これはほとんどの場合間違いです。ガードレス スクリプトにカスタム クラスがあり、それを pickle ファイルに保存した場合、別のスクリプトでそれを unpickle すると、ガードレス スクリプトのインポートがトリガーされ、前の箇条書きで概説したのと同じ問題が発生します。
長い回答
これがなぜ、どのように重要なのかをよりよく理解するには、一歩下がって、Python がスクリプトを初期化する方法と、それがモジュールのインポート メカニズムとどのように相互作用するかを理解する必要があります。
Python インタープリターがソース ファイルを読み取るときは、次の 2 つの処理が行われます。
のようないくつかの特別な変数を設定し
__name__
、ファイル内にあるすべてのコードを実行します。
__name__
これがどのように機能するか、そしてPython スクリプトで常に表示されるチェックに関する質問とどのように関係するかを見てみましょう。
コードサンプル
少し異なるコード サンプルを使用して、インポートとスクリプトがどのように機能するかを調べてみましょう。 というファイルに次のコードがあるとしますfoo.py
。
# Suppose this is foo.py.
print("before import")
import math
print("before function_a")
def function_a():
print("Function A")
print("before function_b")
def function_b():
print("Function B {}".format(math.sqrt(100)))
print("before __name__ guard")
if __name__ == '__main__':
function_a()
function_b()
print("after __name__ guard")
特殊変数
Python インタープリタがソース ファイルを読み取るとき、最初にいくつかの特殊変数を定義します。この場合、__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
名前を変数に割り当てます。つまり、"foo"
__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 文ずつ実行します。この説明に沿って進むことができるように、コード サンプルの横に別のウィンドウを開くことをお勧めします。
いつも
文字列を
"before import"
(引用符なしで)出力します。モジュールをロードし
math
、それを という変数に割り当てます。これは、 を次の にmath
置き換えることと同じです( は、文字列を受け取って実際のインポートをトリガーする Python の低レベル関数であることに注意してください)。import math
__import__
# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
文字列 を出力します
"before function_a"
。ブロックを実行して
def
関数オブジェクトを作成し、その関数オブジェクトを という変数に割り当てますfunction_a
。文字列 を出力します
"before function_b"
。2 番目の
def
ブロックを実行し、別の関数オブジェクトを作成して、それを という変数に割り当てますfunction_b
。文字列 を出力します
"before __name__ guard"
。
モジュールがメインプログラムの場合のみ
- モジュールがメイン プログラムである場合、 が
__name__
実際に に設定されていることがモジュールによって確認され"__main__"
、 2 つの関数が呼び出され、文字列"Function A"
と が出力されます"Function B 10.0"
。
モジュールが他のモジュールにインポートされた場合のみ
- (代わりに) モジュールがメイン プログラムではなく、別のプログラムによってインポートされた場合、ではなく
__name__
となり、ステートメントの本体はスキップされます。"foo"
"__main__"
if
いつも
"after __name__ guard"
どちらの場合も文字列が出力されます。
まとめ
要約すると、2 つのケースで印刷される内容は次のとおりです。
# What gets printed if foo is the main program
before import
before function_a
before function_b
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 function_a
before function_b
before __name__ guard
after __name__ guard
なぜこのように動作するのでしょうか?
.py
なぜこのようなことが必要なのか、不思議に思うかもしれません。他のプログラムやモジュールによってモジュールとして使用でき、またメイン プログラム自体としても実行できるファイルを書きたい場合があります。例:
モジュールはライブラリですが、ユニット テストやデモを実行するスクリプト モードが必要です。
モジュールはメイン プログラムとしてのみ使用されますが、いくつかのユニット テストがあり、テスト フレームワークは
.py
スクリプトなどのファイルをインポートして特別なテスト関数を実行することによって機能します。モジュールをインポートしているという理由だけでスクリプトを実行させないようにする必要があります。モジュールは主にメインプログラムとして使用されますが、上級ユーザー向けにプログラマーフレンドリーな API も提供します。
これらの例以外にも、Python でスクリプトを実行するには、いくつかの魔法の変数を設定してスクリプトをインポートするだけなので、便利です。スクリプトの「実行」は、スクリプトのモジュールをインポートすることの副作用です。
思考の糧
質問: 複数のチェック ブロックを使用できますか
__name__
? 回答: そうするのは奇妙ですが、言語ではそれを止めることはできません。次のように記述します。コマンドラインで と
foo2.py
記述すると、何が起きるでしょうか。なぜでしょうか。python foo2.py
# Suppose this is foo2.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters
def function_a():
print("a1")
from foo2 import function_b
print("a2")
function_b()
print("a3")
def function_b():
print("b")
print("t1")
if __name__ == "__main__":
print("m1")
function_a()
print("m2")
print("t2")
foo3.py
さて、チェックを外したら何が起こるか考えてみましょう__name__
:
# Suppose this is foo3.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters
def function_a():
print("a1")
from foo3 import function_b
print("a2")
function_b()
print("a3")
def function_b():
print("b")
print("t1")
print("m1")
function_a()
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")