[解決!Python]argparseモジュールを使ってコマンドライン引数を処理するには:解決!Python
argparseモジュールを使い、コマンドラインを通して渡される位置引数/オプション引数を処理する方法を紹介する。
argparseモジュールの基本(位置引数)
import argparse
parser = argparse.ArgumentParser(description='add two integers')
parser.add_argument('x', type=int, help='an integer to be added')
parser.add_argument('y', type=int, help='an integer to be added')
args = parser.parse_args()
result = args.x + args.y
print(result)
「--option value」形式のオプション引数
import argparse
parser = argparse.ArgumentParser(description='add two integers')
#parser.add_argument('-x', type=int)
#parser.add_argument('-y', type=int)
parser.add_argument('-x', type=int, default=0)
parser.add_argument('-y', type=int, default=0)
args = parser.parse_args()
result = args.x + args.y
print(result)
「--option」形式のオプション引数(フラグ、スイッチ)
import argparse
parser = argparse.ArgumentParser(description='add two integer')
parser.add_argument('-s', '--switch1', action='store_true')
parser.add_argument('-t', '--switch2', action='store_true')
args = parser.parse_args()
print(f'switch1: {args.switch1}, switch2: {args.switch2}')
if args.switch1:
print('switch1 is on')
else:
print('swithc1 in off')
if args.switch2:
print('switch is on')
else:
print('switch2 is off')
コマンドライン引数に与える値の数を指定
import argparse
parser = argparse.ArgumentParser(description='add 2 integers')
parser.add_argument('--opt1', nargs=2) # --opt1に続けて2つの値を指定
parser.add_argument('--opt2', nargs='?') # --opt2の後に値を1つ指定してもよい
parser.add_argument('--opt3', nargs='*') # --opt3に続けて0個以上の値を指定
parser.add_argument('--opt4', nargs='+') # --opt4に続けて1つ以上の値を指定
parser.add_argument('pos', nargs='*') # 残りは全て位置引数としてposに格納される
args = parser.parse_args()
print(f'args.opt1: {args.opt1}')
print(f'args.opt2: {args.opt2}')
print(f'args.opt3: {args.opt3}')
print(f'args.opt4: {args.opt4}')
print(f'args.pos: {args.pos}')
コマンドライン引数の指定を必須とする
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('x') # 位置引数はデフォルトで指定が必須
parser.add_argument('y', nargs='*', default=99) # 位置引数だが省略可能
parser.add_argument('-o', '--option', required=True)
args = parser.parse_args()
print(f'args.x: {args.x}, args.y: {args.y}, args.option: {args.option}')
相互排他的なスイッチの作成
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
#group = parser.add_mutually_exclusive_group()
group.add_argument('--quiet', action='store_true')
group.add_argument('--verbose', action='store_true')
args = parser.parse_args()
if args.quiet:
print('in quiet mode')
elif args.verbose:
print('in verbose mode')
else:
print('default mode')
argparseモジュールの使い方
Pythonスクリプトに与えるコマンドライン引数の処理には、前回に紹介したsys.argv属性を使えるが、複雑なコマンドライン処理をするならPythonに標準添付のargparseモジュールが便利に使える。
このモジュールの使い方を簡単にまとめると次のようになる。
- argparseモジュールをインポートする
- argparse.ArgumentParserクラスのインスタンスを作成する
- add_argumentメソッドでコマンドライン引数の解析方法を追加していく
- parse_argsメソッドでPythonスクリプトに与えられたコマンドライン引数を解析する
- スクリプトに与えられたコマンドライン引数の値がparse_argsメソッドの戻り値に格納される
この流れを表すシンプルな例を以下に示す。
import argparse # argparseモジュールのインポート
parser = argparse.ArgumentParser() # ArgumentParserクラスのインスタンスを生成
parser.add_argument('x', type=int) # コマンドライン引数の解析方法を追加(1)
parser.add_argument('y', type=int) # コマンドライン引数の解析方法を追加(2)
args = parser.parse_args() # コマンドライン引数の解析
result = args.x + args.y # 戻り値に格納された値を使用
print(result)
argparseモジュールをインポートしたら、ArgumentParserクラスのインスタンスを作成しているが、このときには幾つかの引数を指定できる。詳しくはPythonのドキュメント「ArgumentParser オブジェクト」を参照されたい。ここではdescription引数の指定例を以下に示す。
parser = argparse.ArgumentParser(description='add two integers')
このようにすると、Pythonスクリプトの実行時に「-h」「--help」オプションを指定したときに表示されるヘルプメッセージにdescription引数に指定した値が含まれるようになる。
argparseモジュールでは、コマンドライン引数を位置引数とオプション引数の2種類に大別している。上のコードでadd_argumentメソッドを使って追加しているのは2つの位置引数「x」と「y」だ(オプション引数についてはこの後取り上げる)。「type=int」として、それらの型がint(整数)であることも指定されているのが分かる。なお、型を指定しない場合、コマンドライン引数は文字列としてスクリプトに渡される。コマンドライン引数の型がハッキリしているのであれば、type引数に型を指定するようにしよう。
先ほどのdescription引数と同様に、コマンドライン引数の説明がヘルプメッセージに表示されるようにするには、add_argumentメソッド呼び出し時にhelp引数にそのテキストを指定すればよい。
parser.add_argument('x', type=int, help='an integer to be added')
parser.add_argument('y', type=int, help='an integer to be added')
この後、parse_argsメソッドを呼び出すと、スクリプトに与えられたコマンドライン引数をsys.argv属性を介して取得して、それらが解析される。その結果、位置引数xとyに指定された値がその戻り値の中に格納され、引数名と同じ名前の属性としてアクセスできるようになる。上のコードでは、戻り値は変数argsに代入されているので、「args.x」「args.y」のようにして、指定されたデータ型の値(ここではint型)として使用できる。
以下に実行例を幾つか示す(ファイル名は「argtest1.py」とする)。
% python3 argtest1.py
usage: argtest1.py [-h] x y
argtest1.py: error: the following arguments are required: x, y
これはコマンドライン引数を何も指定せずに、スクリプトを実行した結果だ。最初に表示されている「usage」は、このスクリプトの使い方を簡単に説明したもので、argparseモジュールによるものだ。次の行は2つの位置引数が指定されていないために表示されたエラーメッセージとなっている。
argparseモジュールを使っているスクリプトに「-h」「--help」オプションを指定すると、そのスクリプトのヘルプが表示される。以下に例を示す。
usage: argtest1.py [-h] x y
add two integers
positional arguments:
x an integer to be added
y an integer to be added
options:
-h, --help show this help message and exit
上の方にArgumentParserクラスのインスタンス生成時にdescription引数に指定した「add two integers」が表示されているのが分かる。その下には2つの位置引数の説明が、最後にオプション引数の説明が表示される(上の実行例は、先ほど述べたように、add_argumentメソッド呼び出し時にhelp引数に説明のテキストを入れたもの)。
最後に、2つの位置引数を指定してスクリプトを実行した例を示す。
% python3 argtest1.py 10 20
30
オプション引数の追加
上で見た位置引数は基本的には指定が必須のコマンドライン引数となる。これに対して、基本的には指定が必須ではないコマンドライン引数としてオプション引数がある。オプション引数を指定しない場合、その値はNoneとなる。
また、オプション引数には「--オプション引数 値」のように値を指定するものと、「--オプション引数」のように値を指定しないものがある。後者は、スクリプトの振る舞いを変更するためのスイッチやフラグと呼ばれるものだ。まずは前者の使い方を見てみよう。
「--option value」形式のオプション引数
オプション引数を追加するのにも、add_argumentメソッドを呼び出せばよい。とのときには、最初に指定する変数名をハイフン「-」で始める。以下に例を示す。
import argparse
parser = argparse.ArgumentParser(description='add two integers')
parser.add_argument('-x', type=int)
parser.add_argument('-y', type=int)
#parser.add_argument('-x', type=int, default=0)
#parser.add_argument('-y', type=int, default=0)
args = parser.parse_args()
result = args.x + args.y
print(result)
最初の例とほぼ同じなので、ここではadd_argumentメソッド呼び出しにだけ注目する。上で述べたように、変数名が「-x」「-y」とハイフンで始まっている点に注目しよう。こうすることで、argparseモジュールはこれらがオプション引数であると認識する。最初の2行では、型がintであることのみを指定している。よって、これらを省略した場合、その値はNoneとなる(これも既に述べた通りだ)。
2つのコマンドライン引数を指定せずに実行した例を以下に示す(ファイル名は「argtest2.py」とする)。
% python3 argtest2.py
Traceback (most recent call last):
File "/Users/.../test/argtest2.py", line 10, in <module>
result = args.x + args.y
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
オプション引数を指定しなかったのでデフォルト値であるNoneとNoneを加算しようとしてTypeError例外が発生した。このような事態を避けるには、上のスクリプトでコメントアウトしているコードのように、default引数にオプション引数のデフォルト値を指定しておくとよい。
parser.add_argument('-x', type=int, default=0)
parser.add_argument('-y', type=int, default=0)
コメントアウトを入れ替えて、実行した結果を以下に示す。
% python3 argtest2.py
0
今度はデフォルト値が0となったので問題なく計算できた。
値を指定するタイプのオプション引数は、「--オプション引数 値」または「-省略形 値」のように指定する。そのため、位置引数のように渡したい値だけを指定するとエラーとなる。以下はその例だ。
% python3 argtest2.py 10 20
usage: argtest2.py [-h] [-x X] [-y Y]
argtest2.py: error: unrecognized arguments: 10 20
そうではなく、以下のように指定する。
% python3 argtest2.py -x 10 -y 20
30
「--option」形式のオプション引数(フラグ、スイッチ)
後に値を続けない「--option」形式のオプションは、スクリプトの動作を変えるようなスイッチあるいはフラグとして使用することが多い。例えば、pythonコマンドに「-V」オプションまたは「--version」オプションを指定すると、そのバージョンを表示して、コマンドの実行が終了する。
このような形のオプションでは、それが指定されたときにはTrue/Falseを保存するようにする。ただし、このときには「type=bool」のようにtype引数を使うのではなく、action引数を使用する。action引数には以下のような値を指定できる(一部を抜粋)。
- store:オプション引数に続けた指定された値を保存する。デフォルトのactionであり、これまでのスクリプトでは実際にはこのアクションが指定されていたと考えられる
- store_true:そのオプションに対応する値としてTrueを保存する。このアクションが指定されたオプションのデフォルト値はFalseとなる
- store_false:そのオプションに体操する値としてFalseを保存する。このアクションが指定されたオプションのデフォルト値はTrueとなる
この他にも、同じオプションが複数回指定された場合にその数をカウントするcountなどもあるが、詳細についてはPythonのドキュメント「action」を参照されたい。
デフォルトでは実行されない処理を、あるオプションが指定されたら実行するようにするならstore_trueを、逆にデフォルトでは実行される処理を抑制するようなオプションであればstore_falseを指定して、スクリプト内ではif文などで処理を分岐するような使い方になるだろう。
以下に使用例を示す。
import argparse
parser = argparse.ArgumentParser(description='add two integer')
parser.add_argument('-s', '--switch1', action='store_true')
parser.add_argument('-t', '--switch2', action='store_true')
args = parser.parse_args()
print(f'switch1: {args.switch1}, switch2: {args.switch2}')
if args.switch1:
print('switch1 is on')
else:
print('swithc1 in off')
if args.switch2:
print('switch is on')
else:
print('switch2 is off')
add_argumentメソッド呼び出しでは、ハイフンが1つで始まる省略形のオプション名と、長いオプション名が指定されている。こうすることで、「-s」と「--switch1」のどちらを使ってもこのオプションを指定できるようになる。actionにはどちらのオプション引数もstore_trueを指定しているので、これらのオプションを指定すると、parse_argsメソッドの戻り値に含まれる、これらに対応する属性(switch1属性とswitch2属性)にはTrueが指定される。
実行例を以下に示す(ファイル名は「argtest3.py」とする)。何も指定せずにスクリプトを実行すると次のようになる。
% python3 argtest3.py
switch1: False, switch2: False
swithc1 in off
switch2 is off
このときには、どちらのオプションも指定されていないので、対応する属性はどちらもFalseとなっている。その後のif文の処理でもelse節のコードが実行されている。
今度は「--switch1」オプションを指定した場合だ。
% python3 argtest3.py --switch1
switch1: True, switch2: False
switch1 is on
switch2 is off
このときには、switch1属性がTrueとなりif文ではif節が実行されている。「--switch2」オプションを指定した場合はその逆になっている。
% python3 argtest3.py --switch2
switch1: False, switch2: True
swithc1 in off
switch is on
最後に、「-s」「-t」という省略形のオプションを指定した例だ。これらのオプション指定も可能なことを確認してほしい。
% python3 argtest3.py -s -t
switch1: True, switch2: True
switch1 is on
switch is on
コマンドライン引数に与える値の数
オプション引数と位置引数のどちらでも、その引数に複数の値を指定できるようにadd_argumentメソッド呼び出しで設定可能だ。可変引数のような処理ができると思えばよいだろう。これにはnargs引数に以下のような値を指定する。
- 整数:指定しただけの数の値を受け取る
- '?':0個か1個の値を受け取る
- '*':0個以上の値を受け取る
- '+':1個以上の値を受け取る
整数/'*'/'+'を指定した場合、受け取った値はリストに格納される。「nargs=1」を指定しても、値が対応する属性の値となるのではなく、要素が1個のリストが作成されるので注意しよう。
以下に使用例を示す。
import argparse
parser = argparse.ArgumentParser(description='add 2 integers')
parser.add_argument('--opt1', nargs=2) # --opt1に続けて2つの値を指定
parser.add_argument('--opt2', nargs='?') # --opt2の後に値を1つ指定してもよい
parser.add_argument('--opt3', nargs='*') # --opt3に続けて0個以上の値を指定
parser.add_argument('--opt4', nargs='+') # --opt4に続けて1つ以上の値を指定
parser.add_argument('pos', nargs='*') # 残りは全て位置引数としてposに格納される
args = parser.parse_args()
print(f'args.opt1: {args.opt1}')
print(f'args.opt2: {args.opt2}')
print(f'args.opt3: {args.opt3}')
print(f'args.opt4: {args.opt4}')
print(f'args.pos: {args.pos}')
4つのオプション引数には上で述べた値がそれぞれ指定されている。1つの位置引数は任意の個数の値を受け取るようになっている。
実行例を以下に示す。「--opt1」オプションでは「nargs=2」だったので、値を2つ受け取る。そこで以下のように実行するとどうなるだろう。
% python3 argtest4.py --opt1 1 2 3 4 5
args.opt1: ['1', '2']
args.opt2: None
args.opt3: None
args.opt4: None
args.pos: ['3', '4', '5']
opt1属性は2つの値を受け取り、他の値は全て任意の個数の値を受け取る位置引数へと渡されたことが分かる。
「--opt2」オプションは「nargs='?'」だったので、これは0個か1個の値を受け取る。
% python3 argtest4.py --opt2 1 2 3 4 5
args.opt1: None
args.opt2: 1
args.opt3: None
args.opt4: None
args.pos: ['2', '3', '4', '5']
そのため、上の実行例ではopt2属性は1個だけを受け取り(この場合、リストは作成されない)、他は位置引数に送られている。
「--opt3」オプションでは「nargs='*'」なので、このオプションに続けて(他のオプションが指定されるまで)置かれた値を全てopt3属性が受け取ることになる。
% python3 argtest4.py 0 --opt3 1 2 3 4 5
args.opt1: None
args.opt2: None
args.opt3: ['1', '2', '3', '4', '5']
args.opt4: None
args.pos: ['0']
この例では「--opt3」オプションよりも前に「0」を指定しているので、位置引数がこれを受け取り、「--opt3」以降の値は全てopt3属性が受け取っている。
「--opt4」オプションでは「nargs='+'」なので、その後に値を1つ以上指定する必要があるが、それ以外は上と同様だ。このオプションに続いて値を指定しなかった場合にエラーとなるかどうかは実際に試してみてほしい。
% python3 argtest4.py 0 --opt4 1 2
args.opt1: None
args.opt2: None
args.opt3: None
args.opt4: ['1', '2']
args.pos: ['0']
コマンドライン引数の指定を必須とする
位置引数は基本的に指定が必須だが、オプション引数は基本的に指定が必須ではない。だが、特定のオプションは常に指定するようにしてほしいこともある。そのようなときには、add_argumentメソッドのrequired引数にTrueを指定すればよい。
位置引数を省略可能とする例と併せて以下にコードを示す。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('x') # 位置引数はデフォルトで指定が必須
parser.add_argument('y', nargs='*', default=99) # 位置引数だが省略可能
parser.add_argument('-o', '--option', required=True) # 指定必須のオプション引数
args = parser.parse_args()
print(f'args.x: {args.x}, args.y: {args.y}, args.option: {args.option}')
オプション引数を追加しているadd_argumentメソッド呼び出しでは、required引数をTrueにしている。これだけで、オプションの指定が必須となる。なお、位置引数を省略可能にするにはnargs引数に「?」(0個か1個の値を受け取る)か「*」(0個以上の値を受け取る)を指定した上で、default引数にデフォルト値を指定すればよい。
以下に実行例を示す(ファイル名は「argtest5.py」とする)。まずは何も指定しなかった場合だ。
% python3 argtest5.py
usage: argtest5.py [-h] -o OPTION x [y ...]
argtest5.py: error: the following arguments are required: x, -o/--option
このときには、位置引数xとオプション引数が指定されていないためにエラーとなる。
次に位置引数を1つとオプション引数を指定した場合だ。
% python3 argtest5.py 10 --option foo
args.x: 10, args.y: 99, args.option: foo
この場合は、省略可能とした位置引数yにはデフォルト値である99が格納されている。
最後に位置引数を3つと、オプション引数を指定してみよう。
% python3 argtest5.py 10 20 30 --option foo
args.x: 10, args.y: ['20', '30'], args.option: foo
2つ目の位置引数yは任意の個数の値を受け取るようにしていたので、2つの値がリストとして格納された。
相互排他的なスイッチ
スクリプトの実行時には、さまざまなオプションが指定されるが、それらの中で相互排他的な指定があることもある。例えば、処理の進捗(しんちょく)を一切表示しないようにする--quiteオプションと、処理の進捗を詳細に表示する--verboseオプションが同時に指定されたら困るといった場合だ。
そのようなときには、add_mutually_exclusive_groupメソッドを使って、幾つかのオプションが相互排他的なものであることを示すグループを作成するとよい。サンプルコードを以下に示す。
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
#group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--quiet', action='store_true')
group.add_argument('--verbose', action='store_true')
args = parser.parse_args()
if args.quiet:
print('in quiet mode')
elif args.verbose:
print('in verbose mode')
else:
print('default mode')
この例では、ArgumentParserクラスのインスタンスでadd_mutually_exclusive_groupメソッドを呼び出している。そして、できたグループに対して、add_argumentメソッドを呼び出して、オプションを追加していくことで、それらが相互排他的にしか指定できなくなる。なお、コメントアウトしている行にあるように、「required=True」を指定すると、いずれかのオプションを必ず指定する必要があるようにできる。
以下に実行例を示す。
% python3 argtest6.py
default mode
% python3 argtest6.py --quiet
in quiet mode
% python3 argtest6.py --quiet --verbose
usage: argtest6.py [-h] [--quiet | --verbose]
argtest6.py: error: argument --verbose: not allowed with argument --quiet
最後の実行例では、両方のオプションを指定しているのでエラーとなっている。
Copyright© Digital Advantage Corp. All Rights Reserved.