Python에서는 argparse를 사용하여 양의 정수만 허용하십시오.


164

제목은 내가하고 싶은 것을 요약합니다.

여기 내가 가진 것이 있으며 프로그램이 양수가 아닌 정수를 폭파 시키지는 않지만, 양수가 아닌 정수는 기본적으로 말도 안된다는 정보를 사용자에게 알기를 원합니다.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-g", "--games", type=int, default=162,
                    help="The number of games to simulate")
args = parser.parse_args()

그리고 출력 :

python simulate_many.py -g 20
Setting up...
Playing games...
....................

네거티브 출력 :

python simulate_many.py -g -2
Setting up...
Playing games...

이제는 if args.games부정적인 판단을 위해 if를 추가 할 수 는 있지만 argparse자동 사용량 인쇄를 활용하기 위해 레벨 에서 트랩 을 잡을 방법이 있는지 궁금합니다 .

이상적으로는 다음과 비슷한 것을 인쇄합니다.

python simulate_many.py -g a
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE]
simulate_many.py: error: argument -g/--games: invalid int value: 'a'

이렇게 :

python simulate_many.py -g -2
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE]
simulate_many.py: error: argument -g/--games: invalid positive int value: '-2'

지금 나는 이것을하고 있으며, 나는 행복하다고 생각합니다.

if args.games <= 0:
    parser.print_help()
    print "-g/--games: must be positive."
    sys.exit(1)

답변:


244

이를 활용하여 가능해야합니다 type. 여전히이를 결정하는 실제 방법을 정의해야합니다.

def check_positive(value):
    ivalue = int(value)
    if ivalue <= 0:
        raise argparse.ArgumentTypeError("%s is an invalid positive int value" % value)
    return ivalue

parser = argparse.ArgumentParser(...)
parser.add_argument('foo', type=check_positive)

이것은 기본적으로 perfect_square에 대한 문서 의 기능을 개조 한 예 입니다 argparse.


1
함수가 여러 값을 가질 수 있습니까? 어떻게 작동합니까?
Tom

2
로 변환 int하지 못하면 여전히 읽을 수있는 출력이 있습니까? 아니면 try raise수동으로 변환해야합니까?
NOhs

4
@MrZ 그것은 같은 것을 줄 것이다 error: argument foo: invalid check_positive value: 'foo=<whatever>'. 더 나은 오류 메시지로 예외를 다시 발생시키는 주변 에 try:... 를 추가 할 수 있습니다 except ValueError:.
Yuushi

59

type Yuushi의 답변과 같이 조건 / 검사를 처리하는 데 권장되는 옵션입니다.

특정한 경우 choices상한도 알려진 경우 매개 변수를 사용할 수도 있습니다.

parser.add_argument('foo', type=int, choices=xrange(5, 10))

참고 : python 3.x range대신 사용 하십시오.xrange


3
범위를 생성 한 다음 순환하여 입력의 유효성을 검사하므로 이것이 비효율적이라고 생각합니다. 빠른이 if훨씬 빠릅니다.
TravisThomas

2
@ trav1th 실제로는 가능하지만 문서의 사용법 예입니다. 또한 Yuushi의 대답이 갈 것이라고 대답했습니다. 옵션을 제공하는 것이 좋습니다. 그리고 argparse의 경우 실행 당 한 번 발생하고 생성기 ( xrange)를 사용 하며 추가 코드가 필요하지 않습니다. 그 절충이 가능합니다. 갈 길을 결정하기 위해 각자에게 달려 있습니다.
aneroid

16
벤 저자의 대답에 대한 jgritty의 요점에 대해 더 명확하게하기 위해 choices = xrange (0,1000)은 --help를 사용할 때마다 또는 잘못된 인수가 제공되었습니다. 대부분의 상황에서 좋은 선택은 아닙니다.
biomiker

9

예측 가능한 최대 값과 인수에 대한 최소값이 있으면 빠르고 더러운 방법 choices은 범위와 함께 사용 하는 것입니다.

parser.add_argument('foo', type=int, choices=xrange(0, 1000))

24
단점은 끔찍한 결과물입니다.
jgritty

6
더티에 중점을 둡니다 .
ben 저자

4
jgritty의 요점을 분명히하기 위해 choices = xrange (0,1000)은 --help를 사용할 때마다 또는 잘못된 인수가 제공 될 때마다 1에서 999까지의 정수 목록을 콘솔에 기록합니다. 대부분의 상황에서 좋은 선택은 아닙니다.
biomiker

8

더 간단한 대안은, 특히 서브 클래 싱 argparse.ArgumentParser인 경우 parse_args메소드 내부에서 유효성 검증을 시작하는 것입니다.

이러한 서브 클래스 내부 :

def parse_args(self, args=None, namespace=None):
    """Parse and validate args."""
    namespace = super().parse_args(args, namespace)
    if namespace.games <= 0:
         raise self.error('The number of games must be a positive integer.')
    return namespace

이 기술은 커스텀 콜 러블만큼 멋지지는 않지만 일을합니다.


소개 ArgumentParser.error(message):

이 메소드는 메시지를 포함하는 사용법 메시지를 표준 오류로 인쇄하고 상태 코드 2로 프로그램을 종료합니다.


크레딧 : jonatan의 답변


또는 최소한 print "-g/--games: must be positive."; sys.exit(1)just로 대체하십시오 parser.error("-g/--games: must be positive."). ( jonatan의 답변 과 같은 사용법 .)
aneroid

3

Google 검색에서 누군가 (나와 같은) 사람 이이 질문을 발견 한 경우 모듈 식 접근법을 사용 하여 지정된 범위에서만 argparse 정수를 허용하는보다 일반적인 문제를 깔끔하게 해결하는 방법의 예는 다음과 같습니다.

# Custom argparse type representing a bounded int
class IntRange:

    def __init__(self, imin=None, imax=None):
        self.imin = imin
        self.imax = imax

    def __call__(self, arg):
        try:
            value = int(arg)
        except ValueError:
            raise self.exception()
        if (self.imin is not None and value < self.imin) or (self.imax is not None and value > self.imax):
            raise self.exception()
        return value

    def exception(self):
        if self.imin is not None and self.imax is not None:
            return argparse.ArgumentTypeError(f"Must be an integer in the range [{self.imin}, {self.imax}]")
        elif self.imin is not None:
            return argparse.ArgumentTypeError(f"Must be an integer >= {self.imin}")
        elif self.imax is not None:
            return argparse.ArgumentTypeError(f"Must be an integer <= {self.imax}")
        else:
            return argparse.ArgumentTypeError("Must be an integer")

이를 통해 다음과 같은 작업을 수행 할 수 있습니다.

parser = argparse.ArgumentParser(...)
parser.add_argument('foo', type=IntRange(1))     # Must have foo >= 1
parser.add_argument('bar', type=IntRange(1, 7))  # Must have 1 <= bar <= 7

변수는 foo이제 OP 요청과 같이 양의 정수 만 허용합니다 .

위의 형식 외에도 다음을 사용하여 최대 값 만 가능합니다 IntRange.

parser.add_argument('other', type=IntRange(imax=10))  # Must have other <= 10
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.