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

======================================================================

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

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

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

どちらも Python のモジュールに関わる機能です。 １つ目はユーザーがどう
モジュールを使うか、２つ目はモジュールとモジュールがどうやりとりするか
に関係します。 詳細は以下で説明します。 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`!')

       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

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

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