コマンドラインでの引数とオプション処理
Pythonスクリプトをコマンドとして実行させるときに、ファイル名やオプションをパラメタとして与えられるようになっていると汎用的なプログラムとして利用しやすくなります。
コマンドラインで与えられるパラメタには次のものがあります。
引数(Argument):スクリプトに渡されるパラメータです。
必須パラメタであるのに指定されていない場合は、通常はエラーが発生します。
オプション(Option):名前が示すように、これは任意のパラメータです。
通常は --file=filepath などのように、オプション名とオプション引数のペアで与えます。
フラグ(Flag):特定の動作の有効/無効を指示するための特別なオプションです。
例: --help、--version
コマンドラインでの引数
Python の sysモジュールにある sys.argv のリストを参照すると、コマンドラインで与えられた引数を受け取ることができます。
code: 0501_sys_argv.py
import sys
print('number of argument: ', len(sys.argv))
print(__file__)
for n, arg in enumerate(sys.argv):
print(f'argv{n} = {arg}') これを実行すると次のようになります。
code: bash
$ python 0501_sys_argv.py 2 4 6
number of argument: 4
0501_sys_argv.py
__file__ と sys.argv[0]には、スクリプトのファイル名がセットされます。
オプションの処理する
スクリプトをコマンドラインで実行するときにオプションを指示できるようにしておくと、スクリプトの汎用性が高まります。コマンドラインでのオプションの与え方は、LINUX系プラットフォームでは、マイナス記号(-) に続けてキーワードを与える形式が一般的です。
オプションはオプション引数を持つものもあります。オプション引数を取らないものは、フラグと呼ばれることもあります。
オプションの例:
--help: ヘルプメッセージを表示させる / ロングオプション
-h: ヘルプメッセージを表示させる / --help の短縮形 / ショートオプション
--version: バージョン情報を出力する
--file=ファイルパス: ファイルパスをオプションとして与える / オプション引数
-f ファイルパス: --file=ファイルパス の短縮形
--verbose=レベル : 冗長な出力をする
レベルで指定した数値が高いほど詳細な出力になる
-v / -vv / -vvv : -v/-v -v/ -v -v -v と同じ
--verbose=レベル と同様。
--debug : デバッグ出力をする / デバッグ機能を有効にする
デバッグに必要な情報を出力を実装していて、通常はオフになっている。
こうしたオプション処理を sys.argv[] のリストをパースして処理すると、オプションの指定順序の対応、short/longなど指定形式の対応、オプションを追加したいときの修正などが煩雑になってしまい、保守性と可読性が悪くなってしまいます。
Python ではたくさんのオプション処理のためのモジュールを利用することができます。
argparser: Python標準モジュール
python-fire: オプション解析を自動処理する拡張モジュール
argparser の使用例
argparser モジュールのparserオブジェクトの add_argument()メソッドを使って、パラメタを個別に定義してゆきます。
argparser モジュールを使うと使用方法(Usageメッセージ)やヘルプメッセージは、自動的に作成してくれます。
code: 0502_argparse.py
import argparse
parser = argparse.ArgumentParser(description ='Search some files')
# nargs 引数の数を指定
# nargs='*': 0もしくはそれ以上 nargs='+': 1もしくはそれ以上
parser.add_argument(dest ='filenames', metavar ='filename', nargs ='*')
parser.add_argument('-p', '--pat', metavar ='pattern',
required = True, dest ='patterns',
action ='append',
help ='text pattern to search for')
parser.add_argument('-v', dest ='verbose',
action ='store_true', help ='verbose mode')
parser.add_argument('-o', dest ='outfile',
action ='store', help ='output file')
parser.add_argument('--overwrite', dest ='overwrite',
action ='store', choices = {'yes', 'no'},
default ='no', help ='Overwrite if file existing')
args = parser.parse_args()
print(args)
まずは、ヘルプメッセージを表示してみましょう。
code: bash
$ python 0502_argparse.py --help
Search some files
positional arguments:
filename
optional arguments:
-h, --help show this help message and exit
-p pattern, --pat pattern
text pattern to search for
-v verbose mode
-o OUTFILE output file
--overwrite {no,yes} overwrite if file existing
add_argument() の help= で指定したテキストからヘルプメッセージを生成してくれます。
引数やオプションの順序が異なっても問題なく処理できます。
code: bash
$ python 0502_argparse.py -v -p apple --pat=google sample.csv
$ python 0502_argparse.py -p apple sample.csv dummy.txt
Python-Fire
Python-Fireは、GoogleがリリースしたPythonオブジェクトからコマンドラインインターフェイスを自動生成してくれるライブラリです。 コマンドラインからPythonコードをより簡単にデバッグし、既存のコードへのCLIインターフェイスを簡単に追加することができます。 Python-Fire は拡張モジュールなのでインストールする必要があります。
code: pip
$ pip install fire
使用方法
今、次のような関数があるとします。
code:hello.py
def hello(name="World"):
return f"Hello {name}!"
この関数をCLIアプリケーションとしたい場合は、単に fire.Fire() で関数を呼び出すだけで、既存コードを修正する必要はありません。
code:hello_cli.py
from hello import hello
import fire
fire.Fire(hello)
ヘルプメッセージを表示するためには、--help もしくは -h をオプションで与えます。
code: zsh
% python hello_cli.py --help
fire は組み込み関数 help()のようにヘルプメッセージを表示してくれます。
code: zsh
NAME
hello_cli.py
SYNOPSIS
hello_cli.py <flags>
FLAGS
--name=NAME
code: zsh
% python hello_cli.py
Hello World!
% python hello_cli.py --name Jack
Hello Jack!
複数のオプションが与えられると最後に指定した値が使用されます。
code: zsh
% python hello_cli.py --name Jack --name Eddie
Hello Eddie!
複数の関数があるときはどうするのか?
次のように複数の関数があるファイルについても、fire は対応できます。
code: mymath.py
def add(x, y):
return x + y
def multiply(x, y):
return x * y
def squre(n):
return(n**2)
def cube(n):
return(n**3)
コード修正する場合は、これまでと同様に fire.Fire() を実行するだけです。
code: mymath_cli.py
from mymath import *
if __name__ == '__main__':
import fire
fire.Fire()
ヘルプメッセージを表示してみましょう。
code: zsh
% python mymath_cli.py --help
ファイルにある関数を読み込んで複数のサブコマンドとして受け付けることがわかります。
code: zsh
NAME
mymath_cli.py
SYNOPSIS
mymath_cli.py GROUP | COMMAND
GROUPS
GROUP is one of the following:
fire
The Python Fire module.
COMMANDS
COMMAND is one of the following:
add
multiply
squre
cube
特定の関数だけにCLIを追加したい
デフォルトではスクリプトファイルにあるすべての関数をサブコマンドとして扱いますが、fire.Fire() を呼び出すときに辞書で対象関数を指定することができます。
code: mymath_cli2.py
from mymath import squre, cube
if __name__ == '__main__':
import fire
fire.Fire({
'Squire': squre,
'Cube': cube,
})
ヘルプメッセージを表示してみましょう。
code: zsh
% python mymath_cli2.py --help
code: zsh
NAME
mymath_cli2.py
SYNOPSIS
mymath_cli2.py COMMAND
COMMANDS
COMMAND is one of the following:
Squire
Cube
辞書で与えたキーの文字列がサブコマンド名となります。
可変引数を受け取る関数
次のような可変引数を受け取るような関数の場合でも、fire はうまく処理してくれます。
code: nargs_cli.py
def order_by_length(*items):
"""Orders items by length, breaking ties alphabetically."""
sorted_items = sorted(items, key=lambda item: (len(str(item)), str(item)))
return ' '.join(sorted_items)
if __name__ == '__main__':
import fire
fire.Fire(order_by_length)
code: zsh
% python nargs_cli.py --help
code: zsh
NAME
nargs_cli.py - Orders items by length, breaking ties alphabetically.
SYNOPSIS
DESCRIPTION
Orders items by length, breaking ties alphabetically.
POSITIONAL ARGUMENTS
ITEMS
code: zsh
% python nargs_cli.py Beer Wine Sake
Beer Sake Wine
参考: