Pythonで if __name__ == ‘__main__’ をかっこよく書けるautomainを調べてみる

if __name__ == ‘__main__’をかっこよく書けるautomain | TRIVIAL TECHNOLOGIES on CLOUD」で紹介されていたautomainモジュールについて調べてみた。

Pythonでモジュールが直接実行されたかどうかを判断するとき、一般的には次のように記述する。

def main():  
    # do something

if __name__ == '__main__':
    main()  

automainモジュールを使うと、これを次のようにかっこよく書くことができる。

from automain import *  

@automain  
def main():  
    # do something

automainモジュールのコードを読む前に、ちょっとおさらい。

__name__には、直接実行されたときには’__main__’、importされたときはモジュール名が入る。

test.py

def main():
    print __name__

if __name__ == '__main__':
    main()

sample.py

import test
test.main()

直接実行したときには、__main__が出力される。

$ python test.py
__main__

importしたときは、モジュール名’test’が出力される。

$ python sample.py
test

だから「if __name__ == ‘__main__’:」でモジュールが直接実行されたかどうかがわかる。

さて、automainモジュールを見てみよう。

def automain(func):
    import inspect
    parent = inspect.stack()[1][0]
    name = parent.f_locals.get('__name__', None)
    if name == '__main__':
        func()

まず最初の行から。

import inspect

inspectモジュールは、型チェック・ソースコードの取得・クラス/関数から情報を取得・インタープリタのスタック情報の調査、の機能を持つ。

次の行。

parent = inspect.stack()[1][0]

inspect.stack()は呼び出し元スタックのフレームレコードのリストを返す。
フレームレコードは長さ6のタプルで、フレームオブジェクト・ファイル名・実行中の行番号・関数名・コンテキストのソース行のリスト・ソース行リストの実行中行のインデックスを格納している。

inspect.stack()の返値のリストの値は、[automainモジュールのフレームレコード,automain関数呼び出し元のフレームレコード]となる。

フレームレコードの最初の要素はフレームオブジェクトだから、parentはautomain関数の呼び出し元のフレームオブジェクトになる。

次の行を見てみよう。

name = parent.f_locals.get('__name__', None)

f_localsはフレームで参照しているローカル名前空間。
そこから’__name__’の値を取得している。

if name == '__main__':

で、’__main__’と比較して、直接実行されたかどうかを判断するという寸法だ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です