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. 각 옵션 플래그를 한 번만 사용할 수 있도록 설정된 것 같습니다. 여러 인수를 단일 옵션 ( 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 같은 작업에 원하는
존 알라

답변:


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=3그리고 metavar=('url','name','other')?

튜플은 metavar또한 사용할 수 있습니다 nargs='+'nargs='*'; 두 문자열은 [-u A [B ...]]또는 로 사용됩니다 [-u [A [B ...]]].


1
좋은 와우! 도움말 기능이 멀티 파트 옵션의 개별 구성 요소가 무엇을 나타내는 지 보여주는 방식을 좋아합니다. 나는 이것을 사용할 것이다!
John Allard

48

이것은 간단합니다. action='append'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로 제한되는 단일 쉼표로 구분 된 문자열입니다. 두 개 이상의 값이 지정되었는지 확인하려면 값을 사후 처리해야합니다.

>>> 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
훌륭한! 도와 주셔서 감사합니다.
John Allard

2
이것은하지 않습니다 확실히 당신이 원하는 것을 할; 나는 inputX_other_var선택 사항을 놓쳤다 .
chepner

나는 그렇게 논평하기 위해 돌아 왔고, 당신의 방식은 모든 vars가 필요합니다. 그래도 올바른 방향입니다!
John Allard

1
네, 선택적 세 번째 인수를 처리하기위한 몇 가지 옵션으로 업데이트되었습니다.
chepner
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.