モジュールの実行と__name__

Pythonスクリプトでよく使う以下のイディオムですが、今回はこの意味の説明と、pythonコマンドで実行可能なスクリプトの作成方法について説明します。

if __name__ == '__main__':
    # 処理

変数__name__と"__main__"

変数__name__に格納されているもの

まず、__name__という特別な変数ですが、これには現在実行中のモジュールの完全修飾名が格納されます。ただし、いつでもモジュール名が格納されるわけではなく、実行時のトップレベル(いわゆるエントリーポイント)のモジュールの場合は"__main__"という文字列が格納されます。つまり、そのモジュールがスクリプトのエントリーポイントとして実行されたかどうかはこの__name__が__main__かどうかで判定することが可能、ということです。したがって、スクリプトとして実行された場合の挙動は冒頭のif文の後に記述すれば良いわけです。

ただし、__name__に格納される値については他にも例外があります。代表的なものとして、パッケージの__init__.pyが挙げられます。このモジュールの__name__にはパッケージ名が格納されます。ここまでの説明が飲み込めない方も多いと思いますが、次のサンプルを実行してみると理解が深まると思います。

理解を深めるためのサンプル

カレントディレクトリにsample.pyとpkg1パッケージが配置されているものとします。また、pkg1配下には__init__.pyとmod1.pyが配置されているものとします。

.
├── pkg1
│   ├── __init__.py
│   └── mod1.py
└── sample.py

それぞれ以下のコードを記述します。

sample.py

# sample.py
from pkg1 import mod1

def func1():
    print('sample.py : ' + __name__)
    mod1.func1()

if __name__ == '__main__':
    func1() 

pkg1/__init__.py

# __init__.py
print('__init__.py : ' + __name__)

pkg1/mod1.py

# pkg1/mod1.py

def func1():
    print('pkg1/mod1.py : ' + __name__)


if __name__ == '__main__':
    func1() 

コードの解説です。カレントディレクトリのsample.pyを実行すると、パッケージとそのモジュールmod1.pyを読み込みます。それぞれのpythonファイルは__name__の値を表示するだけのプログラムです。また、パッケージ配下のmod1モジュールは実行可能となっています。

 
それではまず、カレントディレクトリのsample.pyを実行してみましょう。

$ python sample.py
__init__.py : pkg1
sample.py : __main__
pkg1/mod1.py : pkg1.mod1

いかがでしょうか。まず、トップレベルのモジュールであるsample.pyの__name__の値は"__main__"であることが確認できます。また、モジュールのmod1の名前はモジュールの完全修飾名(パッケージ名を含んでいる)が格納されています。そして、__init__.pyの__name__にはパッケージ名が格納されています。

一方、mod1.pyを実行してみます。

$ python pkg1/mod1.py 
pkg1/mod1.py : __main__

先ほどモジュールの完全修飾名が格納されていましたが、こんどは"__main__"が格納されていることが確認できます。

-mオプション 実行可能パッケージ __main__.py

さて、if ...で実行可能なスクリプトを作成することができましたが、実はパッケージに対しても可能です。パッケージ配下に__main__.pyという名前のモジュールを作成し、poythonコマンド実行時に-mオプションを付与します。先ほどのpkg1パッケージに以下のように__main__.pyを作成してみましょう。

# pkg/__main__.py
import pkg1.mod1
pkg1.mod1.func1()

-mオプションをつけて実行してみます。

$ python -m pkg1
__init__.py : pkg1
pkg1/mod1.py : pkg1.mod1

__main__.pyが実行されたことが確認できました。

 

実行可能な組込みモジュール例

モジュールとして実行可能なパッケージですが、標準ライブラリには便利なツールとして実行可能なパッケージがいくつか提供されています。例えば、json.toolなんかが有名ですね。これは引数で指定したjson文字列を読みやすくダンプしてくれます。実行例を見てみましょう。sample.jsonというファイルにjson文字列が格納されているものとします。-mオプションを指定して実行すると以下のように出力されます。

$ python -m json.tool sample.json
{
    "key1": 100,
    "key2": [
        1,
        2,
        3,
        4
    ],
    "key3": {
        "key4": 100,
        "key5": 200
    }
}