Argparseチュートリアル
- 著者
- Tshepang Lekhonkhobe
このチュートリアルは、Python標準ライブラリで推奨されるコマンドライン解析モジュールである argparse を簡単に紹介することを目的としています。
ノート
同じタスクを実行する他の2つのモジュールがあります。つまり、 getopt (C言語のgetopt()
に相当)と非推奨の optparse です。 argparse は optparse に基づいているため、使用法が非常に似ていることにも注意してください。
コンセプト
ls コマンドを使用して、この入門チュートリアルで検討する機能の種類を示しましょう。
$ ls
cpython devguide prog.py pypy rm-unused-function.patch
$ ls pypy
ctypes_configure demo dotviewer include lib_pypy lib-python ...
$ ls -l
total 20
drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython
drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide
-rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py
drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy
-rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch
$ ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
...
4つのコマンドから学ぶことができるいくつかの概念:
- ls コマンドは、オプションをまったく使用せずに実行する場合に役立ちます。 デフォルトでは、現在のディレクトリの内容が表示されます。
- デフォルトで提供されるものを超えて必要な場合は、もう少し説明します。 この場合、別のディレクトリ
pypy
を表示する必要があります。 私たちがしたことは、位置引数として知られているものを指定することです。 プログラムは、コマンドラインのどこに表示されるかに基づいて、値をどう処理するかを認識している必要があるため、この名前が付けられています。 この概念は、 cp のようなコマンドに関連しています。このコマンドの最も基本的な使用法はcp SRC DEST
です。 最初の位置はコピーしたいもので、2番目の位置はコピーしたい場所です。 - ここで、プログラムの動作を変更したいとします。 この例では、ファイル名だけでなく、各ファイルの詳細情報を表示します。 その場合の
-l
は、オプションの引数として知られています。 - これはヘルプテキストの抜粋です。 これまで使用したことのないプログラムに出くわすことができ、ヘルプテキストを読むだけでどのように機能するかを理解できるという点で非常に便利です。
基礎
(ほとんど)何もしない非常に単純な例から始めましょう:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
以下は、コードを実行した結果です。
$ python3 prog.py
$ python3 prog.py --help
usage: prog.py [-h]
optional arguments:
-h, --help show this help message and exit
$ python3 prog.py --verbose
usage: prog.py [-h]
prog.py: error: unrecognized arguments: --verbose
$ python3 prog.py foo
usage: prog.py [-h]
prog.py: error: unrecognized arguments: foo
これが起こっていることです:
- オプションなしでスクリプトを実行すると、stdoutに何も表示されません。 あまり役に立ちません。
- 2つ目は、 argparse モジュールの有用性の表示を開始します。 私たちはほとんど何もしていませんが、すでに素晴らしいヘルプメッセージを受け取っています。
--help
オプションは、-h
に短縮することもできますが、無料で入手できる唯一のオプションです(つまり、 指定する必要はありません)。 それ以外を指定するとエラーになります。 しかし、それでも、便利な使用法のメッセージが無料で届きます。
位置引数の紹介
例:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)
そしてコードを実行します:
$ python3 prog.py
usage: prog.py [-h] echo
prog.py: error: the following arguments are required: echo
$ python3 prog.py --help
usage: prog.py [-h] echo
positional arguments:
echo
optional arguments:
-h, --help show this help message and exit
$ python3 prog.py foo
foo
何が起こっているのか:
add_argument()
メソッドを追加しました。これは、プログラムが受け入れるコマンドラインオプションを指定するために使用するものです。 この場合、その機能に合わせてecho
という名前を付けました。- プログラムを呼び出すには、オプションを指定する必要があります。
parse_args()
メソッドは、実際には、指定されたオプション(この場合はecho
)からいくつかのデータを返します。- 変数は、 argparse が無料で実行する「魔法」の形式です(つまり、 その値が格納されている変数を指定する必要はありません)。 また、その名前がメソッド
echo
に指定された文字列引数と一致することにも気付くでしょう。
ただし、ヘルプの表示は見栄えがよく、すべてですが、現時点ではそれほど役に立たないことに注意してください。 たとえば、位置引数としてecho
を取得したことがわかりますが、推測するか、ソースコードを読み取る以外に、それが何をするのかわかりません。 それで、それをもう少し便利にしましょう:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print(args.echo)
そして、次のようになります。
$ python3 prog.py -h
usage: prog.py [-h] echo
positional arguments:
echo echo the string you use here
optional arguments:
-h, --help show this help message and exit
では、もっと便利なことをしてみませんか。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)
以下は、コードを実行した結果です。
$ python3 prog.py 4
Traceback (most recent call last):
File "prog.py", line 5, in <module>
print(args.square**2)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
それはあまりうまくいきませんでした。 これは、 argparse は、特に指定しない限り、指定したオプションを文字列として扱うためです。 それでは、 argparse に、その入力を整数として扱うように指示しましょう。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help="display a square of a given number",
type=int)
args = parser.parse_args()
print(args.square**2)
以下は、コードを実行した結果です。
$ python3 prog.py 4
16
$ python3 prog.py four
usage: prog.py [-h] square
prog.py: error: argument square: invalid int value: 'four'
それはうまくいった。 プログラムは、続行する前に、不正な不正な入力でさらに役立つように終了します。
オプションの引数の紹介
これまで、私たちは位置的な議論で遊んできました。 オプションのものを追加する方法を見てみましょう:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increase output verbosity")
args = parser.parse_args()
if args.verbosity:
print("verbosity turned on")
そして出力:
$ python3 prog.py --verbosity 1
verbosity turned on
$ python3 prog.py
$ python3 prog.py --help
usage: prog.py [-h] [--verbosity VERBOSITY]
optional arguments:
-h, --help show this help message and exit
--verbosity VERBOSITY
increase output verbosity
$ python3 prog.py --verbosity
usage: prog.py [-h] [--verbosity VERBOSITY]
prog.py: error: argument --verbosity: expected one argument
これが起こっていることです:
- プログラムは、
--verbosity
が指定されている場合は何かを表示し、指定されていない場合は何も表示しないように作成されています。 - オプションが実際にオプションであることを示すために、オプションなしでプログラムを実行してもエラーはありません。 デフォルトでは、オプションの引数が使用されていない場合、関連する変数(この場合は
args.verbosity
)に値としてNone
が指定されます。これが、の真理テストに失敗する理由です。 if ステートメント。 - ヘルプメッセージは少し異なります。
--verbosity
オプションを使用する場合は、任意の値を指定する必要があります。
上記の例では、--verbosity
の任意の整数値を受け入れますが、単純なプログラムでは、True
またはFalse
の2つの値のみが実際に役立ちます。 それに応じてコードを変更しましょう:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
そして出力:
$ python3 prog.py --verbose
verbosity turned on
$ python3 prog.py --verbose 1
usage: prog.py [-h] [--verbose]
prog.py: error: unrecognized arguments: 1
$ python3 prog.py --help
usage: prog.py [-h] [--verbose]
optional arguments:
-h, --help show this help message and exit
--verbose increase output verbosity
これが起こっていることです:
- このオプションは、値を必要とするものというよりもフラグになりました。 そのアイデアに一致するようにオプションの名前も変更しました。 ここで、新しいキーワード
action
を指定し、それに値"store_true"
を指定することに注意してください。 これは、オプションが指定されている場合、値True
をargs.verbose
に割り当てることを意味します。 指定しない場合は、False
を意味します。 - フラグが実際に何であるかという真の精神で、値を指定すると文句を言います。
- 別のヘルプテキストに注意してください。
短いオプション
コマンドラインの使用法に精通している場合は、オプションの短いバージョンのトピックについてはまだ触れていないことに気付くでしょう。 それは非常に簡単です:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
そしてここに行きます:
$ python3 prog.py -v
verbosity turned on
$ python3 prog.py --help
usage: prog.py [-h] [-v]
optional arguments:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
新しい機能はヘルプテキストにも反映されていることに注意してください。
位置引数とオプション引数の組み合わせ
私たちのプログラムは複雑さを増し続けています。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbose", action="store_true",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbose:
print("the square of {} equals {}".format(args.square, answer))
else:
print(answer)
そして今、出力:
$ python3 prog.py
usage: prog.py [-h] [-v] square
prog.py: error: the following arguments are required: square
$ python3 prog.py 4
16
$ python3 prog.py 4 --verbose
the square of 4 equals 16
$ python3 prog.py --verbose 4
the square of 4 equals 16
- 私たちは位置的な議論を持ち帰ったので、苦情がありました。
- 順序は重要ではないことに注意してください。
このプログラムに複数の詳細値を持つ機能を戻し、実際にそれらを使用できるようにするにはどうでしょうか。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int,
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
そして出力:
$ python3 prog.py 4
16
$ python3 prog.py 4 -v
usage: prog.py [-h] [-v VERBOSITY] square
prog.py: error: argument -v/--verbosity: expected one argument
$ python3 prog.py 4 -v 1
4^2 == 16
$ python3 prog.py 4 -v 2
the square of 4 equals 16
$ python3 prog.py 4 -v 3
16
これらはすべて、プログラムのバグを明らかにする最後のものを除いて、見栄えがします。 --verbosity
オプションが受け入れることができる値を制限することによってそれを修正しましょう:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
そして出力:
$ python3 prog.py 4 -v 3
usage: prog.py [-h] [-v {0,1,2}] square
prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2)
$ python3 prog.py 4 -h
usage: prog.py [-h] [-v {0,1,2}] square
positional arguments:
square display a square of a given number
optional arguments:
-h, --help show this help message and exit
-v {0,1,2}, --verbosity {0,1,2}
increase output verbosity
この変更は、エラーメッセージとヘルプ文字列の両方にも反映されることに注意してください。
ここで、かなり一般的な、冗長性で遊ぶ別のアプローチを使用してみましょう。 また、CPython実行可能ファイルが独自の冗長性引数を処理する方法とも一致します(python --help
の出力を確認してください)。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display the square of a given number")
parser.add_argument("-v", "--verbosity", action="count",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
特定のオプションの引数の出現回数をカウントする別のアクション「count」を導入しました。
$ python3 prog.py 4
16
$ python3 prog.py 4 -v
4^2 == 16
$ python3 prog.py 4 -vv
the square of 4 equals 16
$ python3 prog.py 4 --verbosity --verbosity
the square of 4 equals 16
$ python3 prog.py 4 -v 1
usage: prog.py [-h] [-v] square
prog.py: error: unrecognized arguments: 1
$ python3 prog.py 4 -h
usage: prog.py [-h] [-v] square
positional arguments:
square display a square of a given number
optional arguments:
-h, --help show this help message and exit
-v, --verbosity increase output verbosity
$ python3 prog.py 4 -vvv
16
- はい、以前のバージョンのスクリプトでは、フラグになりました(
action="store_true"
と同様)。 それは苦情を説明するはずです。 - また、「store_true」アクションと同様に動作します。
- これが「カウント」アクションのデモンストレーションです。 あなたはおそらく以前にこの種の使用法を見たことがあるでしょう。
- また、
-v
フラグを指定しない場合、そのフラグはNone
値を持つと見なされます。 - 当然のことながら、フラグの長い形式を指定すると、同じ出力が得られるはずです。
- 残念ながら、ヘルプ出力は、スクリプトが取得した新しい機能についてあまり有益ではありませんが、スクリプトのドキュメントを改善することでいつでも修正できます(例:
help
キーワード引数を介して)。 - その最後の出力は、プログラムのバグを明らかにします。
修正しましょう:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", action="count",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
# bugfix: replace == with >=
if args.verbosity >= 2:
print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity >= 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
そしてこれはそれが与えるものです:
$ python3 prog.py 4 -vvv
the square of 4 equals 16
$ python3 prog.py 4 -vvvv
the square of 4 equals 16
$ python3 prog.py 4
Traceback (most recent call last):
File "prog.py", line 11, in <module>
if args.verbosity >= 2:
TypeError: '>=' not supported between instances of 'NoneType' and 'int'
- 最初の出力はうまくいき、以前のバグを修正しました。 つまり、2以上の値はできるだけ冗長にする必要があります。
- 3番目の出力はあまり良くありません。
そのバグを修正しましょう:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", action="count", default=0,
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity >= 2:
print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity >= 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
さらに別のキーワードdefault
を導入しました。 他のint値と比較できるように、0
に設定しました。 デフォルトでは、オプションの引数が指定されていない場合、None
値を取得し、int値と比較できないことに注意してください(したがって、 TypeError 例外)。
と:
$ python3 prog.py 4
16
私たちがこれまでに学んだことだけでかなり遠くまで行くことができます、そして私たちは表面を引っかいただけです。 argparse モジュールは非常に強力であり、このチュートリアルを終了する前に、もう少し詳しく説明します。
もう少し進んで
小さなプログラムを拡張して、正方形だけでなく他の力を実行したい場合はどうでしょうか。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
parser.add_argument("-v", "--verbosity", action="count", default=0)
args = parser.parse_args()
answer = args.x**args.y
if args.verbosity >= 2:
print("{} to the power {} equals {}".format(args.x, args.y, answer))
elif args.verbosity >= 1:
print("{}^{} == {}".format(args.x, args.y, answer))
else:
print(answer)
出力:
$ python3 prog.py
usage: prog.py [-h] [-v] x y
prog.py: error: the following arguments are required: x, y
$ python3 prog.py -h
usage: prog.py [-h] [-v] x y
positional arguments:
x the base
y the exponent
optional arguments:
-h, --help show this help message and exit
-v, --verbosity
$ python3 prog.py 4 2 -v
4^2 == 16
これまで、表示されるテキストを変更するために冗長レベルを使用してきたことに注意してください。 次の例では、代わりに詳細レベルを使用して、代わりに more テキストを表示します。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
parser.add_argument("-v", "--verbosity", action="count", default=0)
args = parser.parse_args()
answer = args.x**args.y
if args.verbosity >= 2:
print("Running '{}'".format(__file__))
if args.verbosity >= 1:
print("{}^{} == ".format(args.x, args.y), end="")
print(answer)
出力:
$ python3 prog.py 4 2
16
$ python3 prog.py 4 2 -v
4^2 == 16
$ python3 prog.py 4 2 -vv
Running 'prog.py'
4^2 == 16
競合するオプション
これまで、 argparse.ArgumentParser インスタンスの2つのメソッドを使用してきました。 3つ目のadd_mutually_exclusive_group()
を紹介しましょう。 これにより、互いに競合するオプションを指定できます。 新しい機能がより意味をなすように、プログラムの残りの部分も変更しましょう。--verbose
オプションの反対となる--quiet
オプションを導入します。
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y
if args.quiet:
print(answer)
elif args.verbose:
print("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
print("{}^{} == {}".format(args.x, args.y, answer))
私たちのプログラムはよりシンプルになり、デモンストレーションのためにいくつかの機能が失われました。 とにかく、ここに出力があります:
$ python3 prog.py 4 2
4^2 == 16
$ python3 prog.py 4 2 -q
16
$ python3 prog.py 4 2 -v
4 to the power 2 equals 16
$ python3 prog.py 4 2 -vq
usage: prog.py [-h] [-v | -q] x y
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
$ python3 prog.py 4 2 -v --quiet
usage: prog.py [-h] [-v | -q] x y
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
それは簡単に理解できるはずです。 最後の出力を追加したので、得られる柔軟性を確認できます。 長い形式のオプションと短い形式のオプションを混在させます。
結論を出す前に、ユーザーが知らない場合に備えて、プログラムの主な目的をユーザーに伝えたいと思うでしょう。
import argparse
parser = argparse.ArgumentParser(description="calculate X to the power of Y")
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y
if args.quiet:
print(answer)
elif args.verbose:
print("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
print("{}^{} == {}".format(args.x, args.y, answer))
使用法のテキストがわずかに異なることに注意してください。 [-v | -q]
に注意してください。これは、-v
または-q
のいずれかを使用できますが、両方を同時に使用することはできないことを示しています。
$ python3 prog.py --help
usage: prog.py [-h] [-v | -q] x y
calculate X to the power of Y
positional arguments:
x the base
y the exponent
optional arguments:
-h, --help show this help message and exit
-v, --verbose
-q, --quiet
結論
argparse モジュールは、ここに示されている以上のものを提供します。 そのドキュメントは非常に詳細で徹底的であり、例がたくさんあります。 このチュートリアルを終えたら、圧倒されることなく簡単に消化できるはずです。