[解決済み】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))
解決方法は?
簡単な答え
これは、ユーザーが意図しない時に誤ってスクリプトを起動してしまわないようにするための定型的なコードです。ここでは、スクリプトからガードが省略された場合によくある問題を紹介します。
-
他のスクリプトでガードレススクリプトをインポートした場合(例.
import my_script_without_a_name_eq_main_guard
を実行するようトリガーします。 インポート時に と 2番目のスクリプトのコマンドライン引数を使用する . これはほとんどの場合、間違いです。 -
ガードレススクリプトにカスタムクラスがあり、それをpickleファイルに保存した場合、他のスクリプトでそれをアンピックルすると、ガードレススクリプトのインポートがトリガーされ、前の弾丸で説明したのと同じ問題が発生します。
長い回答
なぜ、そしてどのようにこれが重要なのかをよりよく理解するためには、一歩下がって、Pythonがどのようにスクリプトを初期化し、これがどのようにモジュールのインポート機構と相互作用するのかを理解する必要があります。
Pythonインタプリタがソースファイルを読むときはいつも、次の2つのことを行います。
-
のようないくつかの特殊な変数を設定します。
__name__
を実行し、その後 -
は、そのファイルにあるすべてのコードを実行します。
これがどのように機能するのか、また、あなたが質問した
__name__
のチェックは、Pythonスクリプトでいつも目にするものです。
コードサンプル
少し変わったコードサンプルを使って、インポートとスクリプトがどのように機能するかを探ってみましょう。 というファイルに次のような記述があるとします。
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インタプリタがソースファイルを読み込むとき、最初にいくつかの特殊変数を定義します。この場合、私たちが気にするのは
__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"
をimport文から
__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
. これは、以下のように置き換えることと同じです。import math
を次のように変更します(ただし__import__
はPythonの低レベル関数で、文字列を受け取り、実際のインポートのトリガーとなります)。
# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
-
文字列を表示します。
"before functionA"
. -
を実行するのです。
def
ブロックを作成し、関数オブジェクトを作成し、その関数オブジェクトを変数functionA
. -
文字列を表示します。
"before functionB"
. -
を実行し、2番目の
def
ブロックの中で、別の関数オブジェクトを作成し、それを変数functionB
. -
文字列を表示します。
"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 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.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters
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")
-
を削除するとどうなるか、考えてみましょう。
__name__
でチェックします。foo3.py
:
# Suppose this is foo3.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters
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ショートビデオクローラーチュートリアル
-
[解決済み】IndexError: invalid index to scalar variableを修正する方法
-
[解決済み] 文字列リテラルの前にある'b'文字は何を意味するのでしょうか?
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] __init__.py は何のためにあるのですか?
-
[解決済み] パラメータに**(ダブルスター/アスタリスク)、*(スター/アスタリスク)がありますが、これはどういう意味ですか?
-
[解決済み] Could not find or load main class "とはどういう意味ですか?
-
[解決済み] 文字列フォーマット:% vs. .format vs. f-stringリテラル
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み】Pythonに三項条件演算子はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Python カメの描画コマンドとその例
-
pyCaret効率化乗算器 オープンソース ローコード Python機械学習ツール
-
Python LeNetネットワークの説明とpytorchでの実装
-
FacebookオープンソースワンストップサービスpythonのタイミングツールKats詳細
-
[解決済み】お使いのCPUは、このTensorFlowバイナリが使用するようにコンパイルされていない命令をサポートしています。AVX AVX2
-
[解決済み] データ型が理解できない
-
[解決済み】Flask ImportError: Flask という名前のモジュールがない
-
[解決済み】cアンダースコア式`c_`は、具体的に何をするのですか?
-
[解決済み] Pythonのmainメソッドを理解する【重複】について
-
[解決済み】なぜdef main()を使うのか?) 重複