Python argparse : 최소한 하나의 인수를 필요로합니다.


95

내가 사용하고 argparse파이썬 할 수있는 프로그램 -process, -upload또는 두 가지 모두 :

parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('-process', action='store_true')
parser.add_argument('-upload',  action='store_true')
args = parser.parse_args()

프로그램은 하나 이상의 매개 변수 없이는 의미가 없습니다. argparse하나 이상의 매개 변수를 강제로 선택 하도록 구성 하려면 어떻게 해야합니까?

최신 정보:

댓글에 따라 : 최소한 하나의 옵션으로 프로그램을 매개 변수화하는 Python 방식은 무엇입니까?


9
-x보편적으로 플래그이며 선택 사항입니다. -필요한 경우 잘라냅니다 .

1
process옵션을 지정할 필요없이 기본 동작 을 만들고 해당 옵션이 설정된 upload경우 사용자가이를 변경하도록 허용 할 수 없습니까? 일반적으로 옵션은 선택 사항이므로 이름이됩니다. 필수 옵션은 피해야합니다 ( 문서에도 있음). argparse
팀 Pietzcker

@AdamMatan 질문을 한 지 거의 3 년이 지났지 만 그 안에 숨겨진 도전이 마음에 들었고 이런 종류의 작업에 사용할 수있는 새로운 솔루션의 이점을 사용했습니다.
Jan Vlcinsky 2014 년

답변:


112
if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')

1
이것에 argparse대한 기본 제공 옵션이 없다면 그것은 아마도 유일한 방법 일 것입니다 .
Adam Matan 2011-07-17

31
args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')

3
일반화 된 솔루션의 경우 +1. 또한 vars()**를 사용하여 신중하게 이름이 지정된 옵션을 생성자에 전달하는 데 유용합니다.
Lenna

정확히 내가하고있는 일입니다. 감사!
brentlance

1
댕, 좋아 vars. 나는 방금 .__dict__전에 멍청하다고 느꼈다.
Theo Belaire 2014

1
훌륭한 답변. 모두 "바르"와 "어떤은":-) 나에게 새로웠다
비벡 제이 자

21

'또는 둘 다'부분이 아니라면 (처음에 이것을 놓쳤습니다) 다음과 같이 사용할 수 있습니다.

parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('--process', action='store_const', const='process', dest='mode')
parser.add_argument('--upload',  action='store_const', const='upload', dest='mode')
args = parser.parse_args()
if not args.mode:
    parser.error("One of --process or --upload must be given")

그러나 대신 하위 명령 을 사용하는 것이 더 나은 생각 일 것입니다 .


4
나는 그가 XOR이 아닌 --processOR 을 허용하고 싶어한다고 생각 --upload합니다. 이렇게하면 두 옵션이 동시에 설정되지 않습니다.
phihag

+1. 하위 명령을 언급했기 때문입니다. 그러나 - 누군가가 코멘트에 지적 -x하고 --xxx일반적으로 선택적 매개 변수입니다.
mac

20

나는 이것이 먼지로 오래되었다는 것을 알고 있지만 하나의 옵션을 요구하지만 둘 이상의 (XOR)를 금지하는 방법은 다음과 같습니다.

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-process', action='store_true')
group.add_argument('-upload',  action='store_true')
args = parser.parse_args()
print args

산출:

>opt.py  
usage: multiplot.py [-h] (-process | -upload)  
multiplot.py: error: one of the arguments -process -upload is required  

>opt.py -upload  
Namespace(process=False, upload=True)  

>opt.py -process  
Namespace(process=True, upload=False)  

>opt.py -upload -process  
usage: multiplot.py [-h] (-process | -upload)  
multiplot.py: error: argument -process: not allowed with argument -upload  

4
불행히도 OP는 XOR을 원하지 않습니다. 둘 중 하나 또는 둘 다이지만 아무것도 아니므로 마지막 테스트 케이스가 요구 사항을 충족하지 못합니다.
kdopen

3
@kdopen : 응답자는 이것이 원래 질문의 변형이라는 것을 명확히했습니다. 유용한 것으로 나타났습니다. "하나의 옵션을 요구하지만 둘 이상의 것을 금지하는 방법"아마도 Stack Exchange의 에티켓은 대신 새로운 질문을 요구할 것입니다. . 하지만 ... 나에게 도움을 준이 응답 선물을 가지고
erik.weathers

2
이 게시물은 초기 질문에 대한 답변이 없습니다
Marc

2
이것이 "적어도 하나"라는 질문에 어떻게 대답합니까?
xaxxon

2
불행히도 OP는 XOR을 원하지 않습니다.
duckman_1991 년

8

요구 사항 검토

  • 사용 argparse(나는 이것을 무시할 것입니다)
  • 하나 또는 두 개의 작업을 호출 할 수 있습니다 (적어도 하나는 필요함).
  • Pythonic에 의해 시도하십시오 (차라리 "POSIX"와 같은 이름으로 부르고 싶습니다)

명령 줄에서 생활 할 때 몇 가지 암시 적 요구 사항도 있습니다.

  • 이해하기 쉬운 방식으로 사용자에게 사용법 설명
  • 옵션은 선택 사항입니다.
  • 플래그 및 옵션 지정 허용
  • 다른 매개 변수 (예 : 파일 이름 또는 이름)와 결합 할 수 있습니다.

docopt(파일 managelog.py)을 사용한 샘플 솔루션 :

"""Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args

그것을 실행하십시오 :

$ python managelog.py
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

도움말보기 :

$ python managelog.py -h
Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  P    managelog.py [options] upload -- <logfile>...

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>

그리고 그것을 사용하십시오 :

$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log
{'--': True,
 '--pswd': 'secret',
 '--user': 'user',
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': False,
 'upload': True}

짧은 대안 short.py

더 짧은 변형이있을 수 있습니다.

"""Manage logfiles
Usage:
    short.py [options] (process|upload)... -- <logfile>...
    short.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args

사용법은 다음과 같습니다.

$ python short.py -V process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 1,
 'upload': 1}

"process"및 "upload"키에 대한 부울 값 대신 카운터가 있습니다.

우리는 다음 단어의 중복을 막을 수 없습니다.

$ python short.py -V process process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 2,
 'upload': 1}

결론

좋은 명령 줄 인터페이스를 디자인하는 것은 때때로 어려울 수 있습니다.

명령 줄 기반 프로그램에는 여러 측면이 있습니다.

  • 명령 줄의 좋은 디자인
  • 적절한 파서 선택 / 사용

argparse 많은 것을 제공하지만 가능한 시나리오를 제한하고 매우 복잡해질 수 있습니다.

docopt 가독성을 보존하고 유연성의 높은 수준을 제공하면서 상황이 훨씬 짧은 이동합니다. 사전에서 구문 분석 된 인수를 가져오고 수동으로 (또는라는 다른 라이브러리를 사용하여 schema) 일부 변환 (정수로 변환 ) docopt을 수행하는 경우 명령 줄 구문 분석에 적합 할 수 있습니다 .


docopt에 대해 들어 본 적이 없습니다. 훌륭한 제안입니다!
Ton van den Heuvel

@TonvandenHeuvel 좋아요. 확인하고 싶습니다. 여전히 명령 줄 인터페이스에 대해 선호하는 솔루션으로 사용하고 있습니다.
Jan Vlcinsky

베스트 답변 evar, 자세한 예를 들어 주셔서 감사합니다.
jnovack

5

하나 이상의 매개 변수를 사용하여 Python 프로그램을 실행 해야하는 경우 옵션 접두어 (기본적으로-또는-) 가없는 인수를 추가 하고 설정합니다 nargs=+(최소 하나의 인수 필요). 내가 찾은이 방법의 문제점은 인수를 지정하지 않으면 argparse가 "너무 적은 인수"오류를 생성하고 도움말 메뉴를 인쇄하지 않는다는 것입니다. 해당 기능이 필요하지 않은 경우 코드에서 수행하는 방법은 다음과 같습니다.

import argparse

parser = argparse.ArgumentParser(description='Your program description')
parser.add_argument('command', nargs="+", help='describe what a command is')
args = parser.parse_args()

내가 생각하는 당신이 옵션을 접두사로 인수를 추가 할 때, nargs 전체 인수 파서뿐 아니라 옵션에 적용있다. (내가 평균, 당신이 경우 --option플래그 nargs="+", 다음 --option. 플래그 예상하는 적어도 하나의 인수를 당신이있는 경우 optionnargs="+", 그것은 전체 적어도 하나의 인수를 기대하고있다.)


choices=['process','upload']그 주장에 추가 할 수 있습니다 .
hpaulj 2014-06-10

5

들어 http://bugs.python.org/issue11588 나는 일반화의 방법을 탐구하고 mutually_exclusive_group이 같은 경우를 처리하는 개념.

이 개발을 argparse.py통해 https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py 다음과 같이 작성할 수 있습니다.

parser = argparse.ArgumentParser(prog='PROG', 
    description='Log archiver arguments.')
group = parser.add_usage_group(kind='any', required=True,
    title='possible actions (at least one is required)')
group.add_argument('-p', '--process', action='store_true')
group.add_argument('-u', '--upload',  action='store_true')
args = parser.parse_args()
print(args)

다음을 생성합니다 help.

usage: PROG [-h] (-p | -u)

Log archiver arguments.

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

possible actions (at least one is required):
  -p, --process
  -u, --upload

이것은 '-u', '-up', '--proc --up'등과 같은 입력을받습니다.

오류 메시지가 더 명확해야하지만 https://stackoverflow.com/a/6723066/901925 와 유사한 테스트를 실행 하게됩니다.

usage: PROG [-h] (-p | -u)
PROG: error: some of the arguments process upload is required

궁금합니다.

  • 매개 변수가 kind='any', required=True충분히 명확합니까 (그룹 중 하나를 허용합니다. 하나 이상이 필요함)?

  • 사용법이 (-p | -u)명확합니까? 필수 mutually_exclusive_group은 동일한 결과를 생성합니다. 대체 표기법이 있습니까?

  • phihag's간단한 테스트 보다 더 직관적 인 그룹을 사용하고 있습니까?


add_usage_group이 페이지에서 언급 된 내용을 찾을 수 없습니다 : docs.python.org/2/library/argparse.html ; 문서에 대한 링크를 제공해 주시겠습니까?
P. Myer Nore

@ P.MyerNore, 나는이 답변의 시작 부분에 링크를 제공했습니다. 이것은 생산에 투입되지 않았습니다.
hpaulj

5

이를 수행하는 가장 좋은 방법은 python inbuilt module add_mutually_exclusive_group을 사용하는 것 입니다.

parser = argparse.ArgumentParser(description='Log archiver arguments.')
group = parser.add_mutually_exclusive_group()
group.add_argument('-process', action='store_true')
group.add_argument('-upload',  action='store_true')
args = parser.parse_args()

명령 줄에서 하나의 인수 만 선택하려면 required = True를 그룹의 인수로 사용하십시오.

group = parser.add_mutually_exclusive_group(required=True)

2
이것이 "적어도 하나"를 얻는 방법- "정확히 하나"가되지 않습니까?
xaxxon 19:43에

3
불행히도 OP는 XOR을 원하지 않습니다. OP가 OR을 찾고 있습니다
duckman_1991

이것은 OP의 질문에 대한 답변은 아니지만 내 답변은 어쨌든 감사합니다 ¯_ (ツ) _ / ¯
rosstex

2

하위 파서를 사용할 수 있습니까?

import argparse

parser = argparse.ArgumentParser(description='Log archiver arguments.')
subparsers = parser.add_subparsers(dest='subparser_name', help='sub-command help')
parser_process = subparsers.add_parser('process', help='Process logs')
parser_upload = subparsers.add_parser('upload', help='Upload logs')
args = parser.parse_args()

print("Subparser: ", args.subparser_name)

이제 --help보여줍니다 :

$ python /tmp/aaa.py --help
usage: aaa.py [-h] {process,upload} ...

Log archiver arguments.

positional arguments:
  {process,upload}  sub-command help
    process         Process logs
    upload          Upload logs

optional arguments:
  -h, --help        show this help message and exit
$ python /tmp/aaa.py
usage: aaa.py [-h] {process,upload} ...
aaa.py: error: too few arguments
$ python3 /tmp/aaa.py upload
Subparser:  upload

이러한 하위 구문 분석기에 추가 옵션을 추가 할 수도 있습니다. 또한 그것을 사용하는 대신 dest='subparser_name'주어진 하위 명령에서 직접 호출되는 함수를 바인딩 할 수도 있습니다 (문서 참조).


2

이것은 목적을 달성하고 이것은 또한 argparse 자동 생성 --help출력에서 반영 될 것입니다. 이것은 대부분의 정상적인 프로그래머가 원하는 것입니다 (선택적 인수와도 함께 작동합니다).

parser.add_argument(
    'commands',
    nargs='+',                      # require at least 1
    choices=['process', 'upload'],  # restrict the choice
    help='commands to execute'
)

이에 대한 공식 문서 : https://docs.python.org/3/library/argparse.html#choices


1

작업 목록에 append_const를 사용하고 목록이 채워져 있는지 확인합니다.

parser.add_argument('-process', dest=actions, const="process", action='append_const')
parser.add_argument('-upload',  dest=actions, const="upload", action='append_const')

args = parser.parse_args()

if(args.actions == None):
    parser.error('Error: No actions requested')

상수 내에서 직접 메서드를 지정할 수도 있습니다.

def upload:
    ...

parser.add_argument('-upload',  dest=actions, const=upload, action='append_const')
args = parser.parse_args()

if(args.actions == None):
    parser.error('Error: No actions requested')

else:
    for action in args.actions:
        action()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.