__main__ --- トップレベルのコード環境


Python では、 __main__ という特別な名前が次の二つの重要な用途で使われます:

  1. プログラムのトップレベル環境の名前。 __name__ == '__main__' という式でチェックすることができる。

  2. Python パッケージにおける __main__.py ファイル。

どちらも Python のモジュールに関わる機能です。 1つ目はユーザーがどうモジュールを使うか、2つ目はモジュールとモジュールがどうやりとりするかに関係します。 詳細は以下で説明します。 Python モジュールがどういうものかについては、 モジュール を参照してください。

__name__ == '__main__'

Python モジュールやパッケージがインポートされるとき、 __name__ の値はそのモジュールの名前となります。 通常、インポートされる Python ファイル自体のファイル名から拡張子``.py`` を除いたものとなります:

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

インポートされるファイルがパッケージの一部である場合は、 __name__ にはそのパッケージのパスも含まれます:

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

しかし、モジュールがトップレベルのスクリプト環境で実行される場合は、 __name__'__main__' という文字列になります。

「トップレベルのスクリプト環境」とは

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

以下のものがトップレベルのスクリプト環境となります:

  • インタラクティブプロンプトのスコープ:

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

    $ python helloworld.py
    Hello, world!
    
  • Python インタープリタにPython -m オプションとして渡される Python モジュールまたはパッケージ:

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

    $ echo "import this" | python
    The Zen of Python, by Tim Peters
    
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
    
  • Python インタープリタに -c オプションで渡される Python コード:

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

上記それぞれの場合で、トップレベルのモジュールの __name__ の値が '__main__' となります。

これにより、 __name__ をチェックすれば各モジュールは自分がトップレベル環境で実行されているかどうかを知ることができます。 このことから、モジュールが import 文で初期化された場合以外の場合でのみコードを実行するため、次のコードがしばしば用いられます:

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 functions are often used to create command-line tools by specifying them as entry points for console scripts. When this is done, pip inserts the function call into a template script, where the return value of main is passed into sys.exit(). For example:

sys.exit(main())

Since the call to main is wrapped in sys.exit(), the expectation is that your function will return some value acceptable as an input to sys.exit(); typically, an integer or None (which is implicitly returned if your function does not have a return statement).

By proactively following this convention ourselves, our module will have the same behavior when run directly (i.e. python echo.py) as it will have if we later package it as a console script entry-point in a pip-installable package.

In particular, be careful about returning strings from your main function. sys.exit() will interpret a string argument as a failure message, so your program will have an exit code of 1, indicating failure, and the string will be written to sys.stderr. The echo.py example from earlier exemplifies using the sys.exit(main()) convention.

参考

Python Packaging User Guide contains a collection of tutorials and references on how to distribute and install Python packages with modern tools.

__main__.py in Python Packages

If you are not familiar with Python packages, see section パッケージ of the tutorial. Most commonly, the __main__.py file is used to provide a command-line interface for a package. Consider the following hypothetical package, "bandclass":

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

__main__.py will be executed when the package itself is invoked directly from the command line using the -m flag. For example:

$ python -m bandclass

This command will cause __main__.py to run. How you utilize this mechanism will depend on the nature of the package you are writing, but in this hypothetical case, it might make sense to allow the teacher to search for students:

# bandclass/__main__.py

import sys
from .student import search_students

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

Note that from .student import search_students is an example of a relative import. This import style can be used when referencing modules within a package. For more details, see パッケージ内参照 in the モジュール section of the tutorial.

通常の使われ方

The content of __main__.py typically isn't fenced with an if __name__ == '__main__' block. Instead, those files are kept short and import functions to execute from other modules. Those other modules can then be easily unit-tested and are properly reusable.

If used, an if __name__ == '__main__' block will still work as expected for a __main__.py file within a package, because its __name__ attribute will include the package's path if imported:

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

This won't work for __main__.py files in the root directory of a .zip file though. Hence, for consistency, a minimal __main__.py without a __name__ check is preferred.

参考

See venv for an example of a package with a minimal __main__.py in the standard library. It doesn't contain a if __name__ == '__main__' block. You can invoke it with python -m venv [directory].

See runpy for more details on the -m flag to the interpreter executable.

See zipapp for how to run applications packaged as .zip files. In this case Python looks for a __main__.py file in the root directory of the archive.

import __main__

Regardless of which module a Python program was started with, other modules running within that same program can import the top-level environment's scope (namespace) by importing the __main__ module. This doesn't import a __main__.py file but rather whichever module that received the special name '__main__'.

Here is an example module that consumes the __main__ namespace:

# 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)

Example usage of this module could be as follows:

# 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())

Now, if we started our program, the result would look like this:

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

The exit code of the program would be 1, indicating an error. Uncommenting the line with my_name = "Dinsdale" fixes the program and now it exits with status code 0, indicating success:

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

Note that importing __main__ doesn't cause any issues with unintentionally running top-level code meant for script use which is put in the if __name__ == "__main__" block of the start module. Why does this work?

Python inserts an empty __main__ module in sys.modules at interpreter startup, and populates it by running top-level code. In our example this is the start module which runs line by line and imports namely. In turn, namely imports __main__ (which is really start). That's an import cycle! Fortunately, since the partially populated __main__ module is present in sys.modules, Python passes that to namely. See Special considerations for __main__ in the import system's reference for details on how this works.

The Python REPL is another example of a "top-level environment", so anything defined in the REPL becomes part of the __main__ scope:

>>> 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

Note that in this case the __main__ scope doesn't contain a __file__ attribute as it's interactive.

The __main__ scope is used in the implementation of pdb and rlcompleter.