コマンドライン引数

初回公開:2019/02/09
最終更新:未

【 目次 】

windows10 -python3で検証

sys.argv

pythonでコマンドライン引数にアクセスするにはsysモジュールのargvを使用する。

  • 29.1. sys — システムパラメータと関数 — Python 3.6.5 ドキュメント

    Pythonスクリプトに渡されたコマンドライン引数のリスト。
    argv[0] はスクリプトの名前となりますが、フルパス名かどうかは、OSによって異なります。
    コマンドライン引数に -c を付けて Pythonを起動した場合、 argv[0] は文字列 '-c' となります。
    スクリプト名なしでPythonを起動した場合、 argv[0] は空文字列になります。

argv_test.py

import sys

print("sys.argv=",sys.argv)
print("sys.argv=の型は",type(sys.argv))    # list型

print("引数の数(実際には一つ多くなる)=",len(sys.argv))

for argi in sys.argv:
    print(argi)

実行結果

C:\arg_test> python argv_test.py -a -b xxx
sys.argv= ['argv_test.py', '-a', '-b', 'xxx']
sys.argv=の型は <class 'list'>
引数の数(実際には一つ多くなる)= 4
argv_test.py
-a
-b
xxx

ArgumentParser (argparse)

sys.argvを使う方法はシンプルで解りやすいのだが、UNIX流のコマンドライン引数を簡単に実装したい場合には、Pythonの標準ライブラリであるArgumentParserを使うのが便利である。

公式ドキュメントの「チュートリアル」は

公式ドキュメントの「argparseモジュールのドキュメント」は

他のサイトの参考記事

基礎

(ほとんど)何もしない、とても簡単な例
チュートリアルより引用

ArgumentParserモジュールを使う基本形は以下のコードになる。

argparse_sample0.py

import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
python argparse_sample0.py -h

または

python argparse_sample0.py --help

実行結果

usage: argparse_sample0.py [-h]

optional arguments:
  -h, --help  show this help message and exit

上記のコードを使う事で、 -h, --helpオプションが自動的に実装される。

コマンドライン引数は、位置引数Optional引数とがある。
そして、Optional引数には値を指定するOptional引数もある。
これらの指定方法についてみていく事にする。

位置引数

位置引数は引数を指定する位置によってその意味が決定される
また、位置引数は省略できない必須の引数となる。
但し、add_argumentに名前付き引数default(後述)を指定すると位置引数は省略可能となる場合がある。

位置引数を一つ指定

以下の例は位置引数を一つ指定するプログラムの例

argparse_sample1.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)

引数を指定しないでプログラムを実行

python argparse_sample1.py

位置引数は必須の引数なので以下のようなエラーになる。

実行結果

usage: argparse_sample1.py [-h] echo
argparse_sample1.py: error: the following arguments are required: echo

引数を一つ指定すると

python argparse_sample1.py  xxx

指定した引数が表示される

実行結果

xxx

引数を余分に指定すると

python argparse_sample1.py  xxx yyy

エラーになる。

実行結果

usage: argparse_sample1.py [-h] echo
argparse_sample1.py: error: unrecognized arguments: yyy

コマンドライン引数にヘルプメッセージを指定する

位置引数や後述するOptional引数には、
add_argumentメソッドの名前付き引数helpに引数のヘルプメッセージを指定する事ができる。

argparse_sample2.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo 引数を表示")
args = parser.parse_args()
print(args.echo)
python argparse_sample2.py -h

実行結果

usage: argparse_sample2.py [-h] echo

positional arguments:
  echo        echo 引数を表示

optional arguments:
  -h, --help  show this help message and exit

位置引数の複数指定と位置引数の順序

位置引数はadd_argumentメソッドで指定された順に引数の順番が決定されるようだ。
以下の例は位置引数を3つ指定する例である。

argparse_sample3.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("pos1", help="位置引数1")
parser.add_argument("pos2", help="位置引数2")
parser.add_argument("pos3", help="位置引数3")
args = parser.parse_args()
print("pos1={} , pos2={} , pos3={}".format(args.pos1, args.pos2, args.pos3))
python argparse_sample3.py xxx yyy zzz

実行結果

pos1=xxx , pos2=yyy , pos3=zzz

helpオプションを指定して実行すると

python argparse_sample3.py -h

実行結果

usage: argparse_sample3.py [-h] pos1 pos2 pos3

positional arguments:
  pos1        位置引数1
  pos2        位置引数2
  pos3        位置引数3

optional arguments:
  -h, --help  show this help message and exit

デフォルト値の指定と位置引数の省略

add_argumentメソッドに名前付き引数defaultを指定する事で引数のデフォルト値を指定する事ができる。
add_argumentメソッドに名前付き引数nargs が ?* を指定すると、位置引数では、コマンドライン引数が指定されなかった場合 default の値が使われる。

ここでは、nargsに?を,defaultにデフォルト値を指定する例を示す。

nargsについては後述

argparse_sample4.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("pos1", help="位置引数1", nargs='?',default="aaa")
parser.add_argument("pos2", help="位置引数2")
parser.add_argument("pos3", help="位置引数3", nargs='?',default="ccc")
args = parser.parse_args()
print("pos1={} , pos2={} , pos3={}".format(args.pos1, args.pos2, args.pos3))

位置引数pos1,pos3はデフォルト値が指定されているので省略可能。
従って、pos2の値のみを指定。

python argparse_sample4.py yyy

実行結果

pos1=aaa , pos2=yyy , pos3=ccc

引数を2つ指定すると、最後の引数pos3のみが省略されたものと解釈される。

python argparse_argparse_sample4.py xxx yyy

実行結果

pos1=xxx , pos2=yyy , pos3=ccc

すべての引数を指定

python argparse_sample4.py xxx yyy zzz

実行結果

pos1=xxx , pos2=yyy , pos3=zzz

引数なしで実行すると

python argparse_sample4.py

位置引数pos2は省略では無いのでエラー

実行結果

usage: argparse_sample4.py [-h] [pos1] pos2 [pos3]
argparse_sample3_2.py: error: the following arguments are required: pos2

helpオプションの出力を確認

python argparse_sample4.py -h

pos1とpos3が[]で囲まれているので省略可能な事が確認できる。

実行結果

usage: argparse_sample4.py [-h] [pos1] pos2 [pos3]

positional arguments:
  pos1        位置引数1
  pos2        位置引数2
  pos3        位置引数3

optional arguments:
  -h, --help  show this help message and exit

複雑な位置引数の場合、引数がどの位置引数に代入されるかをよく考えないと混乱するので注意。
位置引数の指定を省略する事は可能だが、そのような場合は次項のOptional引数を使用した方がわかりやすいように思う。
これに更にnargsによって複数の引数値を持つ引数を考慮すると何が何やら。

Optional引数

位置引数が省略できない必須の引数であるのに対してOptional引数は文字どうり省略可能な引数で、位置引数と異なり引数をどの位置に指定しても良い。

Optional引数には値を指定しない引数と値を指定する引数とがある。
ここでは値を指定しない引数を値無しのOptional引数,値付きのOptional引数と呼ぶことにする。

値を指定するOptional引数

値を指定するOptional引数の例を示す。 add_argumentメソッドの第1引数nameに--が付いている。

argparse_sample5.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="出力の詳細度オプション")
args = parser.parse_args()
if args.verbosity:
    print("verbosityオプション値",args.verbosity)
else:
    print("verbosityオプション無し")
    print("args.verbosity=",args.verbosity,type(args.verbosity))

HELPオプションを指定して実行

python argparse_sample5.py -h

実行結果

usage: argparse_sample5.py [-h] [--verbosity VERBOSITY]

optional arguments:
  -h, --help            show this help message and exit
  --verbosity VERBOSITY
                        出力の詳細度オプション

Optional引数に値を指定

python argparse_sample5.py --verbosity 1

実行結果

verbosityオプション値 1

Optional引数の指定を省略

python argparse_sample5.py

Optional引数を指定しない場合、Optional引数の値はNoneに

実行結果

verbosityオプション無し
args.verbosity= None <class 'NoneType'>

最後に、Optional引数に値を指定せずに実行

python argparse_sample5.py --verbosity

引数に値が指定されていないのでエラーに

実行結果

usage: argparse_sample5.py [-h] [--verbosity VERBOSITY]
argparse_sample4.py: error: argument --verbosity: expected one argument

短いオプション

通常、オプションOptional引数は、--verbosityのように--をつけて長い文字列を指定するとともに、-vのような短い文字でも使えるように指定する。
これを実現するには、add_argumentメソッドに複数の引数名を指定する。

argparse_sample6.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbosity", help="出力の詳細度オプション")
args = parser.parse_args()
if args.verbosity:
    print("verbosityオプション値",args.verbosity)
    # print("vオプション値",args.v) 
else:
    print("verbosityオプション無し")

HELPオプションを指定

python argparse_sample6.py -h

実行結果

usage: argparse_sample6.py [-h] [-v VERBOSITY]

optional arguments:
  -h, --help            show this help message and exit
  -v VERBOSITY, --verbosity VERBOSITY
                        出力の詳細度オプション

短いオプションを指定

python argparse_sample6.py -v 1

実行結果

verbosityオプション値 1

長いオプションを指定

python argparse_sample6.py --verbosity 1

実行結果

verbosityオプション値 1

やりがちなことだが、オプション値にアクセスしようとしてargs.vの値を参照しても値はセットされていない。

print("vオプション値",args.v)
python argparse_sample6.py -v 1

実行結果

verbosityオプション値 1
Traceback (most recent call last):
  File "argparse_sample6.py", line 9, in <module>
    print("vオプション値",args.v)
AttributeError: 'Namespace' object has no attribute 'v'

値指定無しのOptional引数

add_argumentメソッドの名前付き引数actionstore_trueを指定すると値指定無しのOptional引数を意味する事になる。

argparse_sample7.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", help="出力の詳細オプション",
                    action="store_true")
args = parser.parse_args()
if args.verbose:
    print("verboseオプションあり")
else:
    print("verboseオプション無し")
print("args.verbose=",args.verbose,type(args.verbose))

英語の微妙な単語の意味合いで、前項のverbosityオプションがverboseオプションに変更されている点に注意。

引数付きでverboseオプションを指定

python argparse_sample7.py -v 1

値指定無しのOptional引数なのでエラー

実行結果

usage: argparse_sample7.py [-h] [-v]
argparse_sample7.py: error: unrecognized arguments: 1

HELPメッセージを確認

python argparse_sample7.py -h

-v, --verboseには値指定が無い事がわかる。

実行結果

usage: argparse_sample7.py [-h] [-v]

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose  出力の詳細オプション
python argparse_sample7.py -v

または

python argparse_sample7.py --verbose

を実行

実行結果

verboseオプションあり
args.verbose= True <class 'bool'>

verboseオプションの指定を省略

python argparse_sample7.py

実行結果

verboseオプション無し
args.verbose= False <class 'bool'>

値指定無しのOptional引数の値の型はbool型になる事に注意。

名前付き引数actionにはstore_falseを指定する事もできて、その場合には論理が反転して、Optional引数ありの場合にFalseに,無しの場合にTrueになる。

Optional引数へのデフォルト値の指定

位置引数と同様、add_argumentメソッドに名前付き引数defaultを指定する事で、Optional引数もデフォルト値の指定が可能

argparse_sample8.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-d", default="デフォルト",help="デフォルト値付きのオプション")
args = parser.parse_args()

print("dオプションの値",args.d)

引数を指定しないで実行

python argparse_sample8.py

デフォルト値が表示される

実行結果

dオプションの値 デフォルト
python argparse_sample8.py -d 新しい値

実行結果

dオプションの値 新しい値

HELPオプションの出力を確認

python argparse_sample8.py -h

実行結果

usage: argparse_sample8.py [-h] [-d D]

optional arguments:
  -h, --help  show this help message and exit
  -d D        デフォルト値付きのオプション

競合するオプション

add_mutually_exclusive_groupメソッドを使うと、互いに競合するオプション(同時には指定できない相互に排他的なオプション)を指定することができる。

ここでは互いに競合する--unixオプションと--windowsオプションを指定する例を示す。

argparse_sample9.py

import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--unix", action="store_true")
group.add_argument("-w", "--windows", action="store_true")
args = parser.parse_args()

if args.unix:
    print("osはunixです")
elif args.windows:
    print("osはwindowsです")
else:
    print("osは未指定です")

実行結果

C:\arg_test> python argparse_sample9.py -h
usage: argparse_sample9.py [-h] [-u | -w]

optional arguments:
  -h, --help     show this help message and exit
  -u, --unix
  -w, --windows

C:\arg_test> python argparse_sample9.py -u
osはunixです

C:\arg_test> python argparse_sample9.py -w
osはwindowsです

C:\arg_test> python argparse_sample9.py
osは未指定です

C:\arg_test> python argparse_sample9.py -u -w
usage: argparse_sample9.py [-h] [-u | -w]
argparse_sample9.py: error: argument -w/--windows: not allowed with argument -u/--unix

位置引数とOptional引数の指定した時の引数の位置関係

Optional引数は引数をどの位置に指定しても良いが、位置引数の場合は引数の位置が固定となる。
位置引数とOptional引数とが複雑に混在した場合、引数の値がどの引数に対応するかに注意。

3つの位置引数と3つのOptional引数を混在させた例を示す。

argparse_sample10.py

import argparse
parser = argparse.ArgumentParser()

parser.add_argument("pos1", help="位置引数1")
parser.add_argument("pos2", help="位置引数2")
parser.add_argument("pos3", help="位置引数3")

parser.add_argument("-o1", "--option1", help="値指定無しのOptional引数1",
                    action="store_true")
parser.add_argument("-o2", "--option2" , help="値指定無しのOptional引数2",
                    action="store_true")
parser.add_argument("-ov", "--optionValue", help="引数を値無しのOptional引数")

args = parser.parse_args()
print("pos1={} , pos2={} , pos3={}".format(args.pos1, args.pos2, args.pos3))
print("option1={} , option2={} , optionValue={}".format(args.option1, args.option2, args.optionValue))

まず、HELPメッセージを確認

python argparse_sample10.py -h

実行結果

usage: argparse_sample10.py [-h] [-o1] [-o2] [-ov OPTIONVALUE] pos1 pos2 pos3

positional arguments:
  pos1                  位置引数1
  pos2                  位置引数2
  pos3                  位置引数3

optional arguments:
  -h, --help            show this help message and exit
  -o1, --option1        値指定無しのOptional引数1
  -o2, --option2        値指定無しのOptional引数2
  -ov OPTIONVALUE, --optionValue OPTIONVALUE
                        引数を値無しのOptional引数
python argparse_sample10.py -o2 xxx -ov opton_value yyy -o1 zzz

実行結果

pos1=xxx , pos2=yyy , pos3=zzz
option1=True , option2=True , optionValue=opton_value

例は示さないが、これに更に省略可能な位置引数がからんでくると更に複雑に。

choices - 指定できる値を限定する

add_argumentメソッドに名前付き引数choicesを指定すると
引数に指定できる値を限定する事ができる。

位置引数にchoicesを設定

位置引数の例を以下に示す。

argparse_sample11.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("pos", choices=["勝ち", "負け","引き分け"], help="結果")
args = parser.parse_args()

print("posの値",args.pos)

「勝ち」,「負け」,「引き分け」以外の値「勝利」を指定するとエラーになる事が確認できる

実行結果

C:\arg_test> python argparse_sample11.py -h
usage: argparse_sample11.py [-h] {勝ち,負け,引き分け}

positional arguments:
  {勝ち,負け,引き分け}  結果

optional arguments:
  -h, --help    show this help message and exit

C:\arg_test> python argparse_sample11.py 勝ち
posの値 勝ち

C:\arg_test> python argparse_sample11.py 負け
posの値 負け

C:\arg_test> python argparse_sample11.py 引き分け
posの値 引き分け

C:\arg_test> python argparse_sample11.py 勝利
usage: argparse_sample11.py [-h] {勝ち,負け,引き分け}
argparse_sample11.py: error: argument pos: invalid choice: '勝利' (choose from '
勝ち', '負け', '引き分け')

Optional引数にchoicesを設定

Optional引数の例を以下に示す。

argparse_sample12.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-r", "--result_option", choices=["勝ち", "負け","引き分け"], help="結果オプション")
args = parser.parse_args()

if args.result_option:
    print("result_optionの値",args.result_option)
else:
    print("result_optionが指定されていない")

実行結果

C:\arg_test> python argparse_sample12.py -h
usage: argparse_sample12.py [-h] [-r {勝ち,負け,引き分け}]

optional arguments:
  -h, --help            show this help message and exit
  -r {勝ち,負け,引き分け}, --result_option {勝ち,負け,引き分け}
                        結果オプション

C:\arg_test> python argparse_sample12.py -r 勝ち
result_optionの値 勝ち

C:\arg_test> python argparse_sample12.py -r 負け
result_optionの値 負け

C:\arg_test> python argparse_sample12.py -r 引き分け
result_optionの値 引き分け

C:\arg_test> python argparse_sample12.py -r 勝利
usage: argparse_sample12.py [-h] [-r {勝ち,負け,引き分け}]
argparse_sample12.py: error: argument -r/--result_option: invalid choice: '勝利'
(choose from '勝ち', '負け', '引き分け')

in演算をサポートしている任意のオブジェクトを choicesに設定

choicesには固定の値のリストだけではなく、range型等のin演算をサポートしている任意のオブジェクトを指定する事ができる。

in演算子については

in演算をサポートしている任意のオブジェクトをchoicesに指定する例を以下に示す。

argparse_sample13.py

import argparse
parser = argparse.ArgumentParser()

parser.add_argument('-i', type=int, choices=range(1, 4),help="1~3の整数値を指定")
parser.add_argument("-c", type=str, choices=list("abc"),help="a,b,cのいずれかの文字を指定")

d={'jack': 4098, 'sape': 413}
parser.add_argument("-k", type=str, choices=d,help="辞書dのキーを指定")
parser.add_argument("-v", type=int, choices=d.values(),help="辞書dの値を指定")

def myfunc(d):
    l=list()
    for key in d:
        l.append("{}-{}".format(key, d[key]))
    return l
parser.add_argument("-kv", type=str, choices=myfunc(d),help="辞書dのkey-valueを指定")

args = parser.parse_args()

# -iで指定された整数値を出力
if args.i:
    print("i=",args.i)

# -cで指定された文字を出力
if args.c:
    print("c=",args.c)

# キーから辞書dの値を出力
if args.k:
    print("value=",d[args.k])

# 値から辞書dのキーを出力
if args.v:
    for key in d:
        if d[key]==args.v:
            print("key=",key)

# キーと値を出力
if args.kv:
    kv=args.kv.split("-")
    print("key={},value={}".format(kv[0],kv[1]))

add_argumentの名前付き引数typeについては次項で述べるが引数値の型を指定する。

-iオプションに1〜3の整数値を,
-cオプションにa,b,cのいずれかの文字を,
-kオプションに辞書dのキーを,
-vオプションに辞書dの値を,
-kvオプションに辞書dのキーと値を-でつなげた文字を
指定する事を選択させられる事になる。

実行結果

C:\arg_test> python argparse_sample13.py -h
usage: argparse_sample13.py [-h] [-i {1,2,3}] [-c {a,b,c}] [-k {jack,sape}]
                            [-v {4098,413}] [-kv {jack-4098,sape-413}]

optional arguments:
  -h, --help            show this help message and exit
  -i {1,2,3}            1〜3の整数値を指定
  -c {a,b,c}            a,b,cのいずれかの文字を指定
  -k {jack,sape}        辞書dのキーを指定
  -v {4098,413}         辞書dの値を指定
  -kv {jack-4098,sape-413}
                        辞書dのkey-valueを指定

C:\arg_test> python argparse_sample13.py -i 2 -c a -k jack -v 413 -kv sape-413
i= 2
c= a
value= 4098
key= sape
key=sape,value=413

無限個の許容範囲を指定

choicesには無限個の許容範囲を指定する方法もあるようで、

上記のサイトに載っているサンプルコードsample3.pyの最後に

    args = parser.parse_args()

を追加してhelpメッセージを表示してみると

実行結果

c\arg_test> python sample3.py -h
usage: sample3.py [-h] [-s {integer, 2 <= x <= +inf}]

LightsOut Solver

optional arguments:
  -h, --help            show this help message and exit
  -s {integer, 2 <= x <= +inf}
                        LightsOut Size

引数の型 typeを使えばどんな型の引数も受け取れる

typeに引数の型指定

これまで、引数の値の型は基本的に文字列として受け取っていたが、
add_argumentメソッドに名前付き引数typeを使って引数の値の型を指定して受け取る事もできる。

argparse_sample14.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-s", type=str, help="str型の値を指定")
parser.add_argument("-i", type=int, help="int型の値を指定")
parser.add_argument("-f", type=float, help="float型の値を指定")
parser.add_argument("-t", type=tuple, help="タプル型の値を指定")
args = parser.parse_args()

if args.s:
    print(args.s,type(args.s))

if args.i:
    print(args.i,type(args.i))

if args.f:
    print(args.f,type(args.f))

if args.t:
    print(args.t,type(args.t))

実行結果

C:\arg_test> python argparse_sample14.py -s xxx -i 123 -f 1e-3 -t "(5, 99.9, 'abc')"
xxx <class 'str'>
123 <class 'int'>
0.001 <class 'float'>
('(', '5', ',', ' ', '9', '9', '.', '9', ',', ' ', "'", 'a', 'b', 'c', "'", ')') <class 'tuple'>

type=tupleとして受け取った結果の型は確かにtuple型ではあるが、指定した意図に反して1文字ずつの要素として格納されている。
list型についても同様である。

また、注意が必要な点として、タプル型の値を指定する時に引用符で囲っている事。
コマンドライン引数では値の途中でスペーズがあると引数の区切りとみなされてしまう。
引用符で囲わないと次のようなエラーになってしまう。

実行結果

C:\arg_test> python argparse_sample14.py -t (5, 99.9, 'abc')
usage: argparse_sample14.py [-h] [-s S] [-i I] [-f F] [-t T]
argparse_sample14.py: error: unrecognized arguments: 99.9, 'abc')

ブール値を扱うときにも注意

type=dictでは辞書型の値を受け取れない

辞書型の値を引数として受け取ろうとして以下のようなコードを記述してもエラーになってしまう。

argparse_sample15.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-d", type=dict, help="辞書型の値を指定")
args = parser.parse_args()

if args.d:
    print(args.d,type(args.d))

実行結果

C:\arg_test> python C:\arg_test> python argparse_sample15.py -d {'jack': 4098, 'sape': 413
usage: argparse_sample15.py [-h] [-d D]
argparse_sample15.py: error: unrecognized arguments: 4098, 'sape': 4139}

argparseモジュールのドキュメントより引用

type キーワード引数により型チェックと型変換を行うことができます。一般的なビルトインデータ型や関数を type 引数の値として直接指定できます:

type= には1つの文字列を引数に受け取って変換結果を返すような任意の呼び出し可能オブジェクトを渡すことができます:

typeに渡せる型というのは、pythonのすべての組み込み型を指定できるわけだは無く、1つの文字列を引数にもつ事ができるコンストラクタを持つ型という事になる。

辞書型のオブジェクトを生成しようとして、以下のコードを実行してもエラーになってしまう。
辞書型は1つの文字列を引数もつコンストラクタが存在しないため。

d=dict("{'jack': 4098, 'sape': 4139}")

実行結果

ValueError: dictionary update sequence element #0 has length 1; 2 is required

では、辞書型の引数値を渡す事はできないのだろうか?
また、tupleやlistk型の値を意図したとおりに受け取るにはどうしたら?
それに対する私の解決策は後で述べる事にする

typeに関数やクラスを指定 -

typeには1つの文字列を引数に持つ任意の関数やクラス(のコンストラクタ)を指定できる

typeには組み込み型だけでなく「1つの文字列を引数に受け取って変換結果を返すような任意の呼び出し可能オブジェクト」を渡すことができる。
つまり、1つの文字列を引数に持つ関数やクラスのコンストラクタを指定する事もできる事になる。

以下のコードは、文字列を小文字に変換するmyfuncという関数を定義してtype引数に指定する事でコマンドライン引数値を小文字に変換するとともに、コマンドライン引数値よりユーザー定義のクラスのオブジェクトを生成する例である。

argparse_sample16.py

import argparse
parser = argparse.ArgumentParser()

def myfunc(str_arg):
    return str_arg.lower()
parser.add_argument("-l", type=myfunc, help="文字列の値を小文字に変換")

class Person(object):
    def __init__(self,name):
        self.name=name
parser.add_argument("-p", type=Person, help="Personクラスのインスタンスを生成")

args = parser.parse_args()

if args.l:
    print(args.l,type(args.l))

if args.p:
    print(args.p.name,type(args.p))

実行結果

C:\arg_test> python argparse_sample16.py -l XXX -p 愚鈍人
xxx <class 'str'>
愚鈍人 <class '__main__.Person'>

任意の型や任意の式の結果を受け取る

typeに1つの文字列を引数に持つ任意の関数やクラス(のコンストラクタ)を指定できる事を利用すると、コマンドライン引数値に1個の値を受け取る任意の型やPythonの構文で許される任意の式を指定する事ができる。

typeに変換関数を指定できる事を利用すれは、念願の辞書型(やtuple型,list型)だけでなく任意の型や任意の式の結果を受け取る事が可能になる。

argparse_sample17.py

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age

import argparse
parser = argparse.ArgumentParser()
def myfunc(str_arg):
    try:
        any_obj=eval(str_arg)
    except:
        raise argparse.ArgumentTypeError("--anytype:pythonでは評価できない式です",str_arg)
    return any_obj
parser.add_argument("--anytype", type=myfunc, help="任意の型や式を指定")

args = parser.parse_args()
if args.anytype:
    print(args.anytype,type(args.anytype))

以下の実行結果はコマンドライン引数に辞書型の値やtuple型,list型、ユーザー定義のクラス,加算演算,complex型の値を指定した例である。

実行結果

C:\arg_test> python argparse_sample17.py --anytype "{'jack': 4098, 'sape': 4139}"
{'jack': 4098, 'sape': 4139} <class 'dict'>

C:\arg_test> python argparse_sample17.py --anytype "(5, 99.9, 'abc')"
(5, 99.9, 'abc') <class 'tuple'>

C:\arg_test> python argparse_sample17.py --anytype "[5, 99.9, 'abc']"
[5, 99.9, 'abc'] <class 'list'>

C:\arg_test> python argparse_sample17.py --anytype "Person('愚鈍人', 99)"
<__main__.Person object at 0x03E02790> <class '__main__.Person'>

C:\arg_test> python argparse_sample17.py --anytype "10+5"
15 <class 'int'>

C:\arg_test> python argparse_sample17..py --anytype "10+5j"
(10+5j) <class 'complex'>

typeとchoicesを組み合わせる - 大文字小文字を区別しない引数値の実装

コマンドライン引数値はadd_argumentメソッドの名前付き引数typeで指定された呼び出し可能オブジェクトによって変換された後、choices引数によって選別される。
この事を利用すると大文字小文字を区別しない引数値の実装が可能になる。

argparseモジュールのドキュメントより引用

choices コンテナーに含まれているかどうかのチェックは、type による型変換が実行された後であることに注意してください。
このため、choices に格納するオブジェクトの型は指定された type にマッチしている必要があります:

argparse_sample18.py

import argparse
parser = argparse.ArgumentParser()

# 大文字を小文字に変換する関数
def myfunc(str_arg):
    return str_arg.lower()
parser.add_argument("-w", type=myfunc, choices=["win32","win64"],help="文字列の値を小文字に変換")

args = parser.parse_args()

if args.w:
    print(args.w)

実行結果

C:\arg_test> python argparse_sample18.py -h
usage: argparse_sample18.py [-h] [-w {win32,win64}]

optional arguments:
  -h, --help        show this help message and exit
  -w {win32,win64}  文字列の値を小文字に変換

C:\arg_test> python argparse_sample18.py -w WIN32
win32

type引数の指定には「1つの文字列を引数に受け取って変換結果を返すような任意の呼び出し可能オブジェクト」を渡すことができるので、関数myfuncの定義を省略してtype引数に直接ラムダ式lambda s : s.lower()やあるいはもっと簡潔にstr.lower指定する事で同じ事が実現できる。

参考記事

ケース情報を失うことを気にするなら、(上記の記事にあるコードを以下に引用。)

import argparse
class mylist(list):
    # list subclass that uses lower() when testing for 'in'
    def __contains__(self, other):
        return super(mylist,self).__contains__(other.lower())
choices=mylist(['win64','win32'])
parser = argparse.ArgumentParser()
parser.add_argument("-p", choices=choices)
print(parser.parse_args(["-p", "Win32"]))

nargs - 1つの引数に複数の値を指定

nargsは

argparseモジュールドキュメントより引用

ArgumentParser オブジェクトは通常1つのコマンドライン引数を1つのアクションに渡します。nargs キーワード引数は1つのアクションにそれ以外の数のコマンドライン引数を割り当てます。

とあるが、ここではあまり深入りしない。
nargsは引数の数を指定する名前付き引数で、複数の引数値を持つ引数を定義できて,引数値はリストに格納されるようだ

また、nargsの値として指定される? とか +*というのはいわゆるワイルドカードっぽい。

nargsを指定する事で、argparse_sample17.pyのようなコードを使わずともlist型の値を取得する事もできるが、それぞれの要素の型は同じ型であるという制限を受けてしまうようだ。

位置引数の例を示す。 次のコードは3個の整数値よりその合計を求める。

argparse_sample19.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("sum", nargs =3 ,type=int, help="3個の整数を指定")

args = parser.parse_args()
if args.sum:
    total=args.sum[0]+args.sum[1]+args.sum[2]
    print("合計:",total)

実行結果

C:\arg_test> python argparse_sample19.py 3 4 5
合計: 12

Optional引数の例を示す。 次のコードはargparse_sample17.pyを修正して任意の型の値を複数個受け取る。

argparse_sample20.py

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

import argparse
parser = argparse.ArgumentParser()

def myfunc(str_arg):
    try:
        any_obj = eval(str_arg)
    except:
        raise argparse.ArgumentTypeError("--anytypes:pythonでは評価できない式です", str_arg)
    return any_obj
parser.add_argument("--anytypes", type=myfunc, nargs="*", help="任意の型や式を1個以上指定")

args = parser.parse_args()
if args.anytypes:
    for anytype in args.anytypes:
        print(anytype, type(anytype))
python argparse_sample20.py --anytypes "{'jack': 4098, 'sape': 4139}" "(5, 99.9, 'abc')" "Person('愚鈍人', 99)" "10+5" "10+5j"

実行結果

{'jack': 4098, 'sape': 4139} <class 'dict'>
(5, 99.9, 'abc') <class 'tuple'>
<__main__.Person object at 0x03E298B0> <class '__main__.Person'>
15 <class 'int'>
(10+5j) <class 'complex'>

dest - Optional引数の属性名を変更

引数の属性名は、以下のように決定される。

argparseモジュールのドキュメントより引用

位置引数のアクションについては、 dest は通常 add_argument() の第一引数として渡します:
...
オプション引数のアクションについては、 dest の値は通常オプション文字列から生成されます。 ArgumentParser は最初の長いオプション文字列を選択し、先頭の -- を除去することで dest の値を生成します。長いオプション文字列が指定されていない場合、最初の短いオプション文字列から先頭の - 文字を除去することで dest を生成します。先頭以外のすべての - 文字は、妥当な属性名になるように _ 文字へ変換されます。

つまり、位置引数の場合は、add_argumentメソッドの第1引数。
そして、Optional引数の場合は最初の長いオプション文字列で、長いオプションが存在しない場合は最初の短いオプション文字列となる。

Optional引数において、add_argumentメソッドの名前付き引数destを指定するとこの属性名を変更する事ができる。

argparse_sample21.py

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--optionlong", dest="other_name", help="dest付きの引数")
args = parser.parse_args()

if args.other_name:
    print(args.other_name)

実行結果

C:\arg_test> python argparse_sample21.py -h
usage: argparse_sample21.py [-h] [-o OTHER_NAME]

optional arguments:
  -h, --help            show this help message and exit
  -o OTHER_NAME, --optionlong OTHER_NAME
                        dest付きの引数

C:\arg_test> python argparse_sample21.py -o XXX
XXX

位置引数の場合には、destを指定するとエラーになってしまう。

metavar - helpに表示される引数の値として示される文字列を指定

argparseモジュールのドキュメントより引用

add_argumentメソッドの名前付き引数metavarに指定するとhelpに表示される引数の値として示される文字列を変更する事ができる。

argparse_sample22.py

import argparse
parser = argparse.ArgumentParser()

parser.add_argument("pos1", help="位置引数1")
parser.add_argument("pos2", metavar="filename", help="位置引数2")

parser.add_argument("--opt1", help="Optional引数1")
parser.add_argument("--opt2", type=int, metavar="N", help="Optional引数2")

args = parser.parse_args()

実行結果

C:\arg_test> python argparse_sample22.py -h
usage: argparse_sample22.py [-h] [--opt1 OPT1] [--opt2 filename] pos1 filename

positional arguments:
  pos1             位置引数1
  filename         位置引数2

optional arguments:
  -h, --help       show this help message and exit
  --opt1 OPT1      Optional引数1
  --opt2 filename  Optional引数2

metavarに指定した文字列により、ユーザーに変数値としてどんな値を指定すれば良いか知らせる事ができる。

ArgumentParserの引数

argparseモジュールのドキュメントより引用

ArgumentParserクラスのコンストラクタにはさまざまな引数を渡す事ができる。
以下はその一部を使ってhelpメッセージの表示を変更する例

argparse_sample23.py

import argparse
parser = argparse.ArgumentParser(
    description="description:プログラムの説明",
    usage="usage:使い方",
    epilog="epilog:引数のヘルプの後で表示されるテキスト"
)

parser.add_argument("pos", help="位置引数")
parser.add_argument("--opt", help="Optional引数")

args = parser.parse_args()

実行結果

C:\arg_test> python argparse_sample23.py -h
usage: usage:使い方

description:プログラムの説明

positional arguments:
  pos         位置引数

optional arguments:
  -h, --help  show this help message and exit
  --opt OPT   Optional引数

epilog:引数のヘルプの後で表示されるテキスト

雑感

ArgumentParserは便利なモジュールであるが、細かいところまでマスターしようと思うと大変。
一応、ここでまとめた機能だけで充分かな。

ページのトップへ戻る