本稿の最後にモジュールの基礎をマスターする上で知っておくべきことを幾つか取り上げておこう。
グローバル変数「__name__」には、あるモジュールがインポートされた場合には、そのモジュール名が、そうではなく「python PythonApplication1.py」のように実行された場合には「__main__」という値が設定される。
そして、この値を調べることで、モジュールがPythonのスクリプトファイルとして実行されているのか、[Interactive]ウィンドウなどの対話環境や他のPythonスクリプトでそのモジュールがインポートされている(つまり、ライブラリとして利用されている)のかを判断でき、それに応じてPythonインタープリターによってモジュールが解釈/実行されたときの挙動を変更できる。
PythonApplication1.pyファイルを以下のように書き換えてみよう。
print(__name__)
def hello(name):
print("hello", name)
def goodbye(name):
print("goodbye", name)
if __name__ == '__main__':
print("hello from Python");
これはスクリプトファイルとして実行されている場合には「hello from Python」とメッセージを表示するが、インポートされた場合にはメッセージを表示しないようにしたものだ(加えて、テスト用にスクリプトの冒頭で変数__name__の値を表示している)。以下にコマンドラインからpythonコマンドで実行したときの結果と、[Interactive]ウィンドウでインポートしたときの結果を示す。
1つ目の画面がコマンドラインからスクリプトとして実行したものだ。変数__name__の値が「__main__」となっていて、if節のブロックの内容が実行されていることが分かる。2つ目の画面は[Interactive]ウィンドウでインポートをした場合のものだ。こちらではファイル名(から拡張子を除いたもの)が変数__name__の値になっていて(モジュール名)、if節のブロックは実行されていない。
このようにすると、以下で説明するコマンドライン引数と組み合わせて、モジュールを単独のプログラムとして実行した場合には、関数定義などを行った後に(C#でいうところのstatic void Mainメソッドを呼び出すのと似た感じで)ユーザーから受け取った引数を処理してその結果をユーザーに返送するようにする一方で、ライブラリモジュールとしてインポートされた場合には、余計な処理を行わないようにできる。
言葉で説明しても分かりにくいので、以下の「コマンドライン引数」項で実際の例を紹介する。
Pythonでコマンドライン引数を処理するには、sysモジュールが提供するリストargvを使用する。まずは簡単な例を示す。ここではPythonApplication1.pyファイルの内容を以下のように書き換えている。
from sys import argv # sys.argvはコマンドライン引数を格納するリスト
if __name__ == '__main__':
print(argv)
print("hello from Python module")
実行結果を以下に示す。
> python PythonApplication1.py arg1 arg2
['PythonApplication1.py', 'arg1', 'arg2']
hello from Python module
結果を見ると分かる通り、argv[0]には実行されるモジュール(スクリプトファイル)の名前が格納される。そのため、「モジュールに渡す引数の数+1」個の要素がsys.argvには渡されることになる。実際の第1引数にはargv[1]、第2引数にはargv[2]のようにしてアクセスできる。
もう1つ例を示す(ここでもPythonApplication1.pyファイルの内容を丸ごと書き換えている)。
from sys import argv
from re import fullmatch # reモジュールから関数fullmatchをインポート
def add(arg1, arg2):
if fullmatch('[-+]{0,1}\d+', str(arg1)) and fullmatch('[-+]{0,1}\d+', str(arg2)):
return "sum: " + str(int(arg1) + int(arg2))
else:
return "concatnate: " + str(arg1) + str(arg2)
if __name__ == '__main__':
if len(argv) < 3:
print("usage: python PythonApplication.py arg1 arg2")
else:
print(add(argv[1], argv[2]))
ここでは上で見たsysモジュールのリストargvに加えて、reモジュール(正規表現モジュール)の関数fullmatchをインポートして、関数addを定義している。関数add内ではreモジュールの関数fullmatchを使って渡された2つの値がどちらも整数として扱えるかどうかを判定して、そうであればその和を、そうでなければ文字列としてそれらを連結している。さまざまな箇所で組み込み関数のintとstrを使って、渡された値を整数化したり文字列化したりしているのは、関数addに実際に渡される値の型が特定できないからだ(例としてあまりよくなかった……)。
そして、スクリプトとして実行されたときにはコマンドライン引数の数を調べて、数が足りなければ、使い方を示すメッセージを表示し、そうでなければコマンドライン引数を渡して関数addを呼び出すようにしている。これ以上の詳細な説明は不要だろう。正規表現についてはレファレンスマニュアルの「6.2. re」を参照してほしい。
これをスクリプトとして実行した結果を以下に示す。
> python PythonApplication1.py 1 -1
sum: 0
> python PythonApplication1.py "hello " world
concatnate: hello world
> python PythonApplication1.py
usage: python PythonApplication.py arg1 arg2
一方、[Interactive]ウィンドウでインポートした場合の結果を以下に示す。
>>> from PythonApplication1 import add
>>> add("100", "200")
'sum: 300'
>>> add("hello ", "world")
'concatnate: hello world'
>>> add(1, 2)
'sum: 3'
今見たようにグローバル変数__name__の値をチェックして、それに応じて処理を切り分けることで、モジュールを独立したスクリプトファイルとしても、ライブラリのようにも使えるようになる。
本稿ではPythonのモジュールの基本を紹介した。次回は複数のモジュールを組織化して扱うための機構である「パッケージ」と、モジュールに関して積み残した事項を紹介する予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.