Pythonのargparseで同じオプションを複数回使用する


82

複数の入力ソースを受け入れ、それぞれに何かを実行するスクリプトを作成しようとしています。このようなもの

./my_script.py \
    -i input1_url input1_name input1_other_var \
    -i input2_url input2_name input2_other_var \
    -i input3_url input3_name
# notice inputX_other_var is optional

しかし、を使用してこれを行う方法を完全に理解することはできませんargparse。各オプションフラグは1回しか使用できないように設定されているようです。複数の引数を単一のオプション(nargs='*'またはnargs='+')に関連付ける方法は知っていますが、それでも-iフラグを複数回使用することはできません。これを達成するにはどうすればよいですか?

明確にするために、私が最後に欲しいのは文字列のリストのリストです。そう

[["input1_url", "input1_name", "input1_other"],
 ["input2_url", "input2_name", "input2_other"],
 ["input3_url", "input3_name"]]

では、複数の入力ソース引数をその単一のオプションに関連付けてみませんか?
TigerhawkT3 2016年

複数の入力ソースのそれぞれに複数の文字列引数が必要なためです。各入力に-iフラグを使用する必要があり、各入力には、連続する-iフラグ間のすべての文字列が含まれます。-iで入力を指定するffmpegのように機能させたい
John Allard 2016年

回答:


96

これは、オプションで繰り返される2つの引数を処理するパーサーです-名前はmetavar:で定義されています

parser=argparse.ArgumentParser()
parser.add_argument('-i','--input',action='append',nargs=2,
    metavar=('url','name'),help='help:')

In [295]: parser.print_help()
usage: ipython2.7 [-h] [-i url name]

optional arguments:
  -h, --help            show this help message and exit
  -i url name, --input url name
                        help:

In [296]: parser.parse_args('-i one two -i three four'.split())
Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']])

これは2 or 3 argumentケースを処理しません(私はそのような範囲を処理するPythonのバグ/問題のために少し前にパッチを書きましたが)。

どのようにして、別の引数の定義についてnargs=3metavar=('url','name','other')

タプルmetavarは、nargs='+'およびnargs='*';とともに使用することもできます。2つの文字列は[-u A [B ...]]または として使用され[-u [A [B ...]]]ます。


1
素敵な!ヘルプ機能が、マルチパートオプションの個々のコンポーネントが何を表しているかを示す方法が気に入っています。これを使用します!
ジョンアラード2016年

48

これは簡単です。action='append'and nargs='*'(または'+')の両方を追加するだけです。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', action='append', nargs='+')
args = parser.parse_args()

それを実行すると、

In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i
...: nput2_name input2_other_var -i input3_url input3_name

In [33]: args.i
Out[33]:
[['input1_url', 'input1_name', 'input1_other_var'],
 ['input2_url', 'input2_name', 'input2_other_var'],
 ['input3_url', 'input3_name']]

2
ありがとう、まさに私が必要としていたもの!:Dサイドノート:可能なデフォルトはタイプのリスト/配列にする必要がある、またはArgparseは失敗します
Tarwin

22

-i3つの引数を受け入れ、appendアクションを使用するように構成する必要があります。

>>> p = argparse.ArgumentParser()
>>> p.add_argument("-i", nargs=3, action='append')
_AppendAction(...)
>>> p.parse_args("-i a b c -i d e f -i g h i".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])

オプションの値を処理するには、単純なカスタムタイプを使用してみてください。この場合、toの引数-iは単一のコンマ区切り文字列であり、分割数は2に制限されています。少なくとも2つの値が指定されていることを確認するには、値を後処理する必要があります。

>>> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append')
>>> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']])

より詳細に制御するには、カスタムアクションを定義します。これは組み込み_AppendAction(によって使用されるaction='append')を拡張しますが、に与えられた引数の数を範囲チェックするだけ-iです。

class TwoOrThree(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        if not (2 <= len(values) <= 3):
            raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values)))
        super(TwoOrThree, self).__call__(parser, namespace, values, option_string)

p.add_argument("-i", nargs='+', action=TwoOrThree)

1
鮮やかさ!ご協力ありがとうございました。
ジョンアラード2016年

2
これはあなたが望むことを完全には行いません。私はそれinputX_other_varがオプションであることを逃しました。
chepner 2016年

私はちょうどそのようにコメントするために戻ってきました、あなたの方法はすべての変数を必要とします。しかし、それは正しい方向です!
ジョンアラード2016年

1
OK、オプションの3番目の引数を処理するためのいくつかのオプションで更新されました。
chepner 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.