__main__ —トップレベルのコード環境—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.10/library/ main
移動先:案内検索

__ main __ —トップレベルのコード環境


Pythonでは、特別な名前__main__が2つの重要な構成に使用されます。

  1. プログラムの最上位環境の名前。__name__ == '__main__'式を使用して確認できます。 と
  2. Pythonパッケージの__main__.pyファイル。

これらのメカニズムは両方ともPythonモジュールに関連しています。 ユーザーがどのように相互作用し、どのように相互作用するか。 それらについては、以下で詳しく説明します。 Pythonモジュールを初めて使用する場合は、チュートリアルセクションモジュールで概要を確認してください。

__name__ == '__main__'

Pythonモジュールまたはパッケージがインポートされると、__name__がモジュールの名前に設定されます。 通常、これは.py拡張子のないPythonファイル自体の名前です。

>>> import configparser
>>> configparser.__name__
'configparser'

ファイルがパッケージの一部である場合、__name__には親パッケージのパスも含まれます。

>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'

ただし、モジュールが最上位のコード環境で実行される場合、その__name__は文字列'__main__'に設定されます。

「トップレベルのコード環境」とは何ですか?

__main__は、トップレベルのコードが実行される環境の名前です。 「トップレベルコード」は、実行を開始する最初のユーザー指定のPythonモジュールです。 プログラムが必要とする他のすべてのモジュールをインポートするため、「トップレベル」です。 「トップレベルコード」は、アプリケーションへのエントリポイントと呼ばれることもあります。

トップレベルのコード環境は次のとおりです。

  • インタラクティブプロンプトの範囲:

    >>> __name__
    '__main__'
  • Pythonモジュールがファイル引数としてPythonインタープリターに渡されます。

    $ python3 helloworld.py
    Hello, world!
  • -m 引数を指定してPythonインタープリターに渡されるPythonモジュールまたはパッケージ:

    $ python3 -m tarfile
    usage: tarfile.py [-h] [-v] (...)
  • Pythonインタープリターが標準入力から読み取るPythonコード:

    $ echo "import this" | python3
    The Zen of Python, by Tim Peters
    
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
  • -c 引数を使用してPythonインタープリターに渡されるPythonコード:

    $ python3 -c "import this"
    The Zen of Python, by Tim Peters
    
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...

これらの各状況で、最上位モジュールの__name__'__main__'に設定されます。

その結果、モジュールは、モジュールがインポートステートメントから初期化されていないときにコードを条件付きで実行するための一般的なイディオムを可能にする独自の__name__をチェックすることにより、トップレベル環境で実行されているかどうかを検出できます。 :

if __name__ == '__main__':
    # Execute when the module is not initialized from an import statement.
    ...

も参照してください

__name__がすべての状況でどのように設定されるかについての詳細は、チュートリアルセクションモジュールを参照してください。


慣用的な使用法

一部のモジュールには、コマンドライン引数の解析や標準入力からのデータのフェッチなど、スクリプトでの使用のみを目的としたコードが含まれています。 このようなモジュールを別のモジュールからインポートする場合、たとえば単体テストを行う場合、スクリプトコードも意図せずに実行されます。

ここで、if __name__ == '__main__'コードブロックを使用すると便利です。 このブロック内のコードは、モジュールがトップレベル環境で実行されない限り実行されません。

if __name___ == '__main__'の下のブロックにできるだけ少ないステートメントを配置すると、コードの明確さと正確さを向上させることができます。 ほとんどの場合、mainという名前の関数は、プログラムの主要な動作をカプセル化します。

# echo.py

import shlex
import sys

def echo(phrase: str) -> None:
   """A dummy wrapper around print."""
   # for demonstration purposes, you can imagine that there is some
   # valuable and reusable logic inside this function
   print(phrase)

def main() -> int:
    """Echo the input arguments to standard output"""
    phrase = shlex.join(sys.argv)
    echo(phrase)
    return 0

if __name__ == '__main__':
    sys.exit(main())  # next section explains the use of sys.exit

モジュールがmain関数内にコードをカプセル化せず、代わりにif __name__ == '__main__'ブロック内に直接配置した場合、phrase変数はモジュール全体に対してグローバルになることに注意してください。 モジュール内の他の関数がローカル名の代わりにグローバル変数を意図せずに使用する可能性があるため、これはエラーが発生しやすくなります。 main関数はこの問題を解決します。

main関数を使用すると、echo関数自体が分離され、他の場所にインポートできるという追加の利点があります。 echo.pyをインポートすると、echo関数とmain関数が定義されますが、__name__ != '__main__'であるため、どちらも呼び出されません。


パッケージングに関する考慮事項

main関数は、コンソールスクリプトのエントリポイントとして指定することにより、コマンドラインツールを作成するためによく使用されます。 これが行われると、 pip は関数呼び出しをテンプレートスクリプトに挿入し、mainの戻り値が sys.exit()に渡されます。 例えば:

sys.exit(main())

mainの呼び出しは sys.exit()でラップされているため、関数が sys.exit()への入力として受け入れ可能な値を返すことが期待されます。 ]; 通常、整数またはNone(関数にreturnステートメントがない場合は暗黙的に返されます)。

この規則に積極的に従うことで、モジュールを直接実行した場合も同じ動作になります(つまり、 python3 echo.py)後で、pip-installableパッケージのコンソールスクリプトエントリポイントとしてパッケージ化した場合と同じです。

特に、main関数から文字列を返す場合は注意が必要です。 sys.exit()は文字列引数を失敗メッセージとして解釈するため、プログラムの終了コードは1で、失敗を示し、文字列はに書き込まれます。 sys.stderr 。 以前のecho.pyの例は、sys.exit(main())規則の使用例です。

も参照してください

Python Packagingユーザーガイドには、最新のツールを使用してPythonパッケージを配布およびインストールする方法に関するチュートリアルとリファレンスのコレクションが含まれています。


Pythonパッケージの__main__.py

Pythonパッケージに慣れていない場合は、チュートリアルのセクションパッケージを参照してください。 最も一般的には、__main__.pyファイルは、パッケージのコマンドラインインターフェイスを提供するために使用されます。 次の架空のパッケージ「bandclass」について考えてみます。

bandclass
  ├── __init__.py
  ├── __main__.py
  └── student.py

__main__.pyは、パッケージ自体が -m フラグを使用してコマンドラインから直接呼び出されたときに実行されます。 例えば:

$ python3 -m bandclass

このコマンドにより、__main__.pyが実行されます。 このメカニズムをどのように利用するかは、作成するパッケージの性質によって異なりますが、この架空のケースでは、教師が生徒を検索できるようにすることが理にかなっている場合があります。

# bandclass/__main__.py

import sys
from .student import search_students

student_name = sys.argv[2] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')

from .student import search_studentsは相対インポートの例であることに注意してください。 このインポートスタイルは、パッケージ内のモジュールを参照するときに使用する必要があります。 詳細については、チュートリアルのモジュールセクションのパッケージ内リファレンスを参照してください。

慣用的な使用法

__main__.pyのコンテンツは通常、if __name__ == '__main__'ブロックで囲われていません。 代わりに、これらのファイルは短く保たれ、他のモジュールから実行する関数です。 これらの他のモジュールは、簡単に単体テストが可能で、適切に再利用できます。

if __name__ == '__main__'ブロックは、インポートされた場合、その__name__属性にパッケージのパスが含まれるため、使用された場合、パッケージ内の__main__.pyファイルに対して引き続き期待どおりに機能します。

>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'

ただし、これは.zipファイルのルートディレクトリにある__main__.pyファイルでは機能しません。 したがって、一貫性を保つために、上記の venv のような最小限の__main__.pyが推奨されます。

も参照してください

標準ライブラリに最小限の__main__.pyが含まれるパッケージの例については、 venv を参照してください。 if __name__ == '__main__'ブロックは含まれていません。 python3 -m venv [directory]で呼び出すことができます。

インタプリタ実行可能ファイルへの -m フラグの詳細については、 runpy を参照してください。

.zip ファイルとしてパッケージ化されたアプリケーションを実行する方法については、 zipapp を参照してください。 この場合、Pythonはアーカイブのルートディレクトリで__main__.pyファイルを探します。


import __main__

Pythonプログラムが開始されたモジュールに関係なく、同じプログラム内で実行されている他のモジュールは、__main__モジュールをインポートすることにより、最上位環境のスコープ(名前空間)をインポートできます。 これは__main__.pyファイルをインポートするのではなく、特別な名前'__main__'を受け取ったモジュールをインポートします。

__main__名前空間を使用するモジュールの例を次に示します。

# namely.py

import __main__

def did_user_define_their_name():
    return 'my_name' in dir(__main__)

def print_user_name():
    if not did_user_define_their_name():
        raise ValueError('Define the variable `my_name`!')

    if '__file__' in dir(__main__):
        print(__main__.my_name, "found in file", __main__.__file__)
    else:
        print(__main__.my_name)

このモジュールの使用例は次のとおりです。

# start.py

import sys

from namely import print_user_name

# my_name = "Dinsdale"

def main():
    try:
        print_user_name()
    except ValueError as ve:
        return str(ve)

if __name__ == "__main__":
    sys.exit(main())

プログラムを開始すると、結果は次のようになります。

$ python3 start.py
Define the variable `my_name`!

プログラムの終了コードは1で、エラーを示します。 my_name = "Dinsdale"で行のコメントを解除すると、プログラムが修正され、ステータスコード0で終了し、成功を示します。

$ python3 start.py
Dinsdale found in file /path/to/start.py

__main__をインポートしても、startモジュールのif __name__ == "__main__"ブロックにあるスクリプト用のトップレベルコードを意図せずに実行しても問題は発生しないことに注意してください。 なぜこれが機能するのですか?

Pythonは、インタープリターの起動時に sys.modules に空の__main__モジュールを挿入し、トップレベルのコードを実行してデータを入力します。 この例では、これはstartモジュールであり、行ごとに実行され、namelyをインポートします。 次に、namely__main__(実際にはstart)をインポートします。 それはインポートサイクルです! 幸い、部分的に入力された__main__モジュールは sys.modules に存在するため、Pythonはそれをnamelyに渡します。 これがどのように機能するかの詳細については、インポートシステムのリファレンスの __ main __ に関する特別な考慮事項を参照してください。

Python REPLは「トップレベル環境」のもう1つの例であるため、REPLで定義されたものはすべて__main__スコープの一部になります。

>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky

この場合、__main__スコープにはインタラクティブであるため、__file__属性が含まれていないことに注意してください。

__main__スコープは、 pdb および rlcompleter の実装で使用されます。