golangの日記

Go言語を中心にプログラミングについてのブログ

python argparse

python.png


argparse のドキュメントは説明が多すぎるので今後使いそうなやつまとめ。なお python の作法についてはあまり詳しくないのであしからず。





目次



パーサーの初期化とヘルプメッセージ

#!/usr/bin/env python3
# coding: utf-8

import argparse

parser = argparse.ArgumentParser(
    prog='prog', # このプログラムの名前。
    description='description',  # usageとオプションとの間に表示するメッセージ
    epilog='epilog',  # オプションの後、最後に表示されるメッセージ。copyrightとか付けたければ使うとよい
    # usage='of %(prog)s', # デフォルトの usage: から始まる行が気に入らない限り指定する必要ない
    # add_help=True,  # -h/–help を追加する。ただしFalseを指定して無効化する以外は設定する必要ない
)

parser.add_argument('-v', '--version',
                    help='output version information',
                    action='version', # versionを指定するとバージョンを表示後そのまま終了してくれる
                    version='%(prog)s 2.0', # %(prog)s で prog='' に設定した名前を入れ込む
                    )

parser.parse_args(['-h']) # 引数を空にすると sys.argv をパースする

ヘルプの出力結果。usage= を設定しない場合 usage: prog [-h] [-v] のようにいい感じにしてくれる。

usage: prog [-h] [-v]

description

optional arguments:
  -h, --help     show this help message and exit
  -v, --version  output version information

epilog



真偽値のオプション

actionstore_false を指定した場合は初期値が True で、オプションを指定したら False になる。store_true は逆で初期値が False

parser.add_argument('-b', '--boolean',
                    help='description',
                    action='store_true',
                    )


文字列のオプション

parser.add_argument('-s', '--string',
                    help='description',
                    # choicesを使って選択肢の中から値を受け取る
                    # choices=['foo', 'bar', 'baz'],

                    # 初期値を入れておくなら default で設定する
                    default='hello',
                    )


数値のオプション

parser.add_argument('-n', '--number',
                    help='description',
                    type=int, # floatにしたい場合は type=float
                    choices=range(1, 10),  # 許容する範囲を指定して簡単なバリデーションする
                    # choices=[3,5,7], というようにリストでも指定できる
                    metavar='1..10', # ヘルプの表示が変わる
                    default=5,
                    )

metavar 設定の有無による違い。

設定なし

usage: name [-h] [-v] [-n {1,2,3,4,5,6,7,8,9}]

optional arguments:
  -n {1,2,3,4,5,6,7,8,9}, --number {1,2,3,4,5,6,7,8,9}

設定あり

usage: name [-h] [-v] [-n 1..10]

optional arguments:
  -n 1..10, --number 1..10


ファイル型のオプション

parser.add_argument('-i', '--input',
                    help='description',
                    # rは読み込み。wなら書き込み。 type=open でもファイル型
                    type=argparse.FileType('r'),
                    )


配列のオプション

# -a foo -a bar -a baz は ['foo', 'bar', 'baz'] というようにリストに追加されていく
parser.add_argument('-a', '--array',
                    help='description',
                    action='append',
                    )


位置引数

使う意味はあまりなさそう。オプション以外の引数。

nargs に指定可能な値

  • ? はオプションとその値以外の最初の引数(残りの引数)
  • *argparse.REMAINDER は残りの引数がリストになる。 ただし残りの引数は args, remain = parser.parse_known_args() を使えばいいので必要ないと思う。
  • 数値 仕様も面倒くさそうだし、何に使うのか全くわからんので割愛
parser.add_argument('first',
                    help='description',
                    nargs='?',
                    )


パース

#!/usr/bin/env python3
# coding: utf-8

import argparse

parser = argparse.ArgumentParser(
    prog='prog',
)

parser.add_argument('-v', '--version',
                    help='Output version information',
                    action='version',
                    version='%(prog)s 2.0',
                    )

# 真偽値
parser.add_argument('-b', '--boolean',
                    help='description',
                    action='store_true',
                    )

# 整数値
parser.add_argument('-n', '--number',
                    help='description',
                    type=int,
                    choices=range(1, 10),
                    metavar='1..10',
                    )

# ファイルの読み込み
parser.add_argument('-i', '--input',
                    help='description',
                    type=argparse.FileType('r'),
                    )

# 配列
parser.add_argument('-a', '--array',
                    help='description',
                    action='append',
                    )

def main():
    # args = parser.parse_args() # 残りの引数が必要ない場合はこれ

    # remain にはオプションとその値以外の残りの引数がリストで入ってる
    args, remain = parser.parse_known_args()
    print(args, remain)

    if args.boolean:
        print("boolean:", args.boolean)

    if args.number is not None:
        print("number:", args.number)

    if args.array is not None:
        print("array:", args.array)

    if args.input is not None:
        # data = args.input.read()
        for line in args.input:
            print(line.strip())
        args.input.close()


if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        # エラーはexitコード 2
        parser.error('Error: {}\n'.format(e))
    else:
        parser.exit(0)


サブコマンド

参考: https://qiita.com/oohira/items/308bbd33a77200a35a3d

#!/usr/bin/env python3
# coding: utf-8

import argparse

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcmd')

subparser_add = subparsers.add_parser('add', help='see `add -h`')
subparser_add.add_argument(
    '-A', '--all', action='store_true', help='all files')

subparser_commit = subparsers.add_parser('commit', help='see `commit -h`')
subparser_commit.add_argument(
    '-m', metavar='MESSAGE', help='commit message')

args = parser.parse_args()

if args.subcmd == None:
    # サブコマンドが指定されない場合はヘルプ表示する
    parser.print_help()

# 参考記事のようにハンドラー関数を使わない場合の振り分け方
if args.subcmd == 'add':
    print('add!')
elif args.subcmd == 'commit':
    print('commit!')



リダイレクトやパイプで値を受け取る

パイプ($ cat hello.txt | python main.py) とか、リダイレクト($ python main.py < hello.txt) でファイルを受け取る。

# is a tty が False のときは stdin に何か飛んでくる
if not sys.stdin.isatty():
    # lines = sys.stdin.readlines()
    for line in sys.stdin:
        print(line)