De titel vat vrijwel samen wat ik zou willen gebeuren.
Hier is wat ik heb, en hoewel het programma niet op een nonpositief geheel getal blaast, wil ik dat de gebruiker wordt geïnformeerd dat een nonpositief geheel getal in principe onzin is.
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()
en de uitvoer:
python simulate_many.py -g 20
Setting up...
Playing games...
....................
Uitgang met een negatief:
python simulate_many.py -g -2
Setting up...
Playing games...
Nu, natuurlijk, kon ik gewoon een if toe toevoegen om te bepalen if args.games
negatief is, maar ik was nieuwsgierig als er een manier was om het op de argparse
te vangen niveau, om te profiteren van het automatische gebruik van het gebruik.
Idealiter zou het iets afdrukken met dit:
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'
Zoals SO:
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'
Voor nu doe ik dit, en ik denk dat ik gelukkig ben:
if args.games <= 0:
parser.print_help()
print "-g/--games: must be positive."
sys.exit(1)
Antwoord 1, Autoriteit 100%
Dit zou mogelijk moeten zijn met behulp van type
. U moet nog steeds een echte methode definiëren die dit voor u beslist:
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)
Dit is eigenlijk alleen een aangepast voorbeeld uit de perfect_square
Functie in de Documenten op argparse
.
Antwoord 2, Autoriteit 28%
type
zou de aanbevolen optie zijn om omstandigheden / cheques aan te pakken, zoals in het antwoord van Yuushi.
In uw specifieke geval kunt u ook de parameter choices
gebruiken als uw bovenlimiet ook bekend is:
parser.add_argument('foo', type=int, choices=xrange(5, 10))
Opmerking: Gebruik range
in plaats van xrange
voor python 3.x
Antwoord 3, Autoriteit 4%
De snelle en vuile manier, als u een voorspelbare MAX en MIN voor uw ARG hebt, is gebruik choices
met een bereik
parser.add_argument('foo', type=int, choices=xrange(0, 1000))
Antwoord 4, Autoriteit 3%
Een eenvoudiger alternatief, vooral als subclassificatie argparse.ArgumentParser
, is het initiëren van de validatie van binnenin de parse_args
methode.
Binnen een dergelijke subklasse:
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
Deze techniek is mogelijk niet zo cool als een aangepaste callable, maar het doet de taak.
Over ArgumentParser.error(message)
:
Deze methode drukt een gebruiksbericht af inclusief het bericht naar de standaardfout en beëindigt het programma met een statuscode van 2.
Krediet: antwoord door jonatan
Antwoord 5, autoriteit 2%
In het geval dat iemand (zoals ik) deze vraag tegenkomt in een Google-zoekopdracht, hier is een voorbeeld van hoe je een modulaire aanpak kunt gebruiken om het meer algemene probleem van het toestaan van argparse integers alleen in een gespecificeerd bereik:
# 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")
Hiermee kun je iets doen als:
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
De variabele foo
staat nu alleen positieve gehele getallentoe, zoals de OP vroeg.
Merk op dat naast de bovenstaande formulieren ook gewoon een maximum mogelijk is met IntRange
:
parser.add_argument('other', type=IntRange(imax=10)) # Must have other <= 10
Antwoord 6
Op basis van Yuushi’s antwoord kun je ook een eenvoudige hulpfunctie definiëren die kan controleren of een getal positief is voor verschillende numerieke typen:
def positive(numeric_type):
def require_positive(value):
number = numeric_type(value)
if number <= 0:
raise ArgumentTypeError(f"Number {value} must be positive.")
return number
return require_positive
De helperfunctie kan worden gebruikt om elk numeriek argumenttype als volgt te annoteren:
parser = argparse.ArgumentParser(...)
parser.add_argument("positive-integer", type=positive(int))
parser.add_argument("positive-float", type=positive(float))