Sprawdź, czy argument opcjonalny argparse jest ustawiony, czy nie

112

Chciałbym sprawdzić, czy użytkownik ustawił opcjonalny argument argparse, czy nie.

Czy mogę bezpiecznie sprawdzić za pomocą isset?

Coś takiego:

if(isset(args.myArg)):
    #do something
else:
    #do something else

Czy to działa tak samo dla argumentów typu float / int / string?

Mógłbym ustawić domyślny parametr i sprawdzić go (np. Ustawić myArg = -1 lub „” dla ciągu znaków lub „NOT_SET”). Jednak wartość, której ostatecznie chcę użyć, jest obliczana dopiero później w skrypcie. Więc ustawiłbym go domyślnie na -1, a później zaktualizowałbym go na coś innego. Wydaje się to trochę niezgrabne w porównaniu ze zwykłym sprawdzaniem, czy wartość została ustawiona przez użytkownika.

Madeleine P. Vincent
źródło
1
Co by isset()było (wskazówka: Python to nie PHP)? Czy hasattr()zamiast tego miałeś na myśli , może? Dlaczego nie skonfigurować argparse, aby zamiast tego ustawić wartość domyślną dla opcji?
Martijn Pieters
@MartijnPieters - tak, prawda. Czy mogę więc po prostu sprawdzić, czy (args.myArg): ...
Madeleine P. Vincent

Odpowiedzi:

146

Myślę, że argumenty opcjonalne (określone za pomocą --) są inicjowane, Nonejeśli nie zostały podane. Możesz więc przetestować is not None. Wypróbuj poniższy przykład:

import argparse as ap

def main():
    parser = ap.ArgumentParser(description="My Script")
    parser.add_argument("--myArg")
    args, leftovers = parser.parse_known_args()

    if args.myArg is not None:
        print "myArg has been set (value is %s)" % args.myArg
Honza Osobne
źródło
Testy „nie ma” i „nie jest żadne” działają dokładnie tak, jak bym chciał i oczekiwał. Dzięki.
Madeleine P. Vincent
39
Niestety to nie działa, wtedy argument ma defaultzdefiniowaną wartość.
kcpr
6
Jeśli chcesz ustawić a default, nadal możesz ustawić nargs='?'i podać constwartość, zgodnie z opisem w dokumentacji . Gdy arg jest nieobecny, defaultjest używany, gdy argument podano bez wartości, to constjest używany, w przeciwnym razie używana jest podana wartość. Tylko z defaulti nargs='?', defaultjest używane, jeśli nie jest podane, Nonejeśli podano bez wartości, w przeciwnym razie podana wartość.
Ioannis Filippidis
@IoannisFilippidis, jeśli używasz action= "store_true"lub action="store_const", const="yourconst"nie możesz użyć tego argumentu do przechowywania innej wartości. To nie zadziała, jeśli używasz ustawień domyślnych. W moim własnym usunąłem wszystkie wartości domyślne z argparser i obsłużyłem wszystko wewnątrz innej funkcji, w def defaults():której mieszam ConfigParser, ArgumentParser i domyślne wartości w kolejności, w jakiej chcę
m3nda
@ erm3nda Nie wspomniałem o ustawieniu pliku action. Odpowiedź nie używa rozszerzenia action. Działania, o których wspomniałeś, są udokumentowane jako zachowujące się w jeden określony sposób (jak zaobserwowałeś). Nie jest jednak konieczne definiowanie akcji.
Ioannis Filippidis
37

Jak zauważa @Honza, is Noneto dobry test. Jest to wartość domyślna default, a użytkownik nie może przekazać ciągu, który go powiela.

Możesz określić inny default='mydefaultvaluei przetestować go. Ale co, jeśli użytkownik określi ten ciąg? Czy to liczy się jako ustawienie, czy nie?

Możesz również określić default=argparse.SUPPRESS. Jeśli użytkownik nie użyje argumentu, nie pojawi się on w argsprzestrzeni nazw. Ale testowanie, które może być bardziej skomplikowane:

args.foo # raises an AttributeError
hasattr(args, 'foo')  # returns False
getattr(args, 'foo', 'other') # returns 'other'

Wewnętrznie parserprzechowuje listę seen_actionsi używa jej do testów „wymaganych” i „wzajemnie wykluczających się”. Ale to nie jest dostępne dla ciebie poza parse_args.

hpaulj
źródło
22

Myślę, że użycie tej opcji default=argparse.SUPPRESSma największy sens. Następnie zamiast sprawdzać, czy argumentem jest not None, sprawdza się, czy argumentem jest inwynikowa przestrzeń nazw.

Przykład:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--foo", default=argparse.SUPPRESS)
ns = parser.parse_args()

print("Parsed arguments: {}".format(ns))
print("foo in namespace?: {}".format("foo" in ns))

Stosowanie:

$ python argparse_test.py --foo 1
Parsed arguments: Namespace(foo='1')
foo in namespace?: True
Nie podano argumentu:
$ python argparse_test.py
Parsed arguments: Namespace()
foo in namespace?: False
Erasmus Cedernaes
źródło
To nie działa dla mnie pod Pythonem 3.7.5 (Anaconda). Otrzymuję wyniktestfoo.py: error: argument --foo: expected one argument
Mike Wise
@MikeWise Jeśli chcesz używać --foobez wartości (czyli 1w moim przykładzie), musisz określić nargs=0w add_argumentfunkcji.
Erasmus Cedernaes
Po prostu skopiowałem i wkleiłem Twój kod zgodnie z opisem w odpowiedzi. Może powinieneś to edytować? Skończyło się na użyciu action='store_true'odpowiedzi poniżej w moim rzeczywistym kodzie.
Mike Wise
@MikeWise, czy uruchomiłeś skrypt jako python argparse_test.py --foo 1?
Erasmus Cedernaes
11

Możesz sprawdzić opcjonalnie przekazaną flagę z opcjami akcji store_truei store_falseargumentami:

import argparse

argparser = argparse.ArgumentParser()
argparser.add_argument('-flag', dest='flag_exists', action='store_true')

print argparser.parse_args([])
# Namespace(flag_exists=False)
print argparser.parse_args(['-flag'])
# Namespace(flag_exists=True)

W ten sposób nie musisz się martwić sprawdzaniem warunkowym is not None. Po prostu sprawdzasz Truelub False. Przeczytaj więcej o tych opcjach w dokumentacji tutaj

Harry Sadler
źródło
1
to nie rozwiązuje problemu, aby wiedzieć, czy argument, który ma wartość, jest ustawiony, czy nie. główny problem polega na tym, aby wiedzieć, czy wartość argumentów pochodzi z defaul = "", czy jest dostarczana przez użytkownika.
m3nda
5

Jeśli Twój argument jest pozycyjny (tj. Nie ma przedrostka „-” ani „-”, tylko argument, zazwyczaj nazwa pliku), możesz użyć parametru nargs, aby to zrobić:

parser = argparse.ArgumentParser(description='Foo is a program that does things')
parser.add_argument('filename', nargs='?')
args = parser.parse_args()

if args.filename is not None:
    print('The file name is {}'.format(args.filename))
else:
    print('Oh well ; No args, no problems')
yPhil
źródło
3

Oto moje rozwiązanie, aby sprawdzić, czy używam zmiennej argparse

import argparse

ap = argparse.ArgumentParser()
ap.add_argument("-1", "--first", required=True)
ap.add_argument("-2", "--second", required=True)
ap.add_argument("-3", "--third", required=False) 
# Combine all arguments into a list called args
args = vars(ap.parse_args())
if args["third"] is not None:
# do something

Może to dać lepszy wgląd w powyższą odpowiedź, której użyłem i dostosowałem do pracy w moim programie.

C.Radford
źródło
0

Aby odpowiedzieć na komentarz @ kcpr do (obecnie zaakceptowanej) odpowiedzi @Honza Osobne

Niestety to nie działa, wtedy argument ma zdefiniowaną wartość domyślną.

można najpierw sprawdzić, czy argument został podany, porównując go z Namespaceobiektem i podając default=argparse.SUPPRESSopcję (patrz odpowiedzi @ hpaulj i @Erasmus Cedernaes oraz ten dokument python3 ), a jeśli nie został podany, ustaw go na wartość domyślną.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--infile', default=argparse.SUPPRESS)
args = parser.parse_args()
if 'infile' in args: 
    # the argument is in the namespace, it's been provided by the user
    # set it to what has been provided
    theinfile = args.infile
    print('argument \'--infile\' was given, set to {}'.format(theinfile))
else:
    # the argument isn't in the namespace
    # set it to a default value
    theinfile = 'your_default.txt'
    print('argument \'--infile\' was not given, set to default {}'.format(theinfile))

Stosowanie

$ python3 testargparse_so.py
argument '--infile' was not given, set to default your_default.txt

$ python3 testargparse_so.py --infile user_file.txt
argument '--infile' was given, set to user_file.txt
calocedrus
źródło
0

Bardzo proste, po zdefiniowaniu zmiennej args przez 'args = parser.parse_args ()' zawiera ona również wszystkie dane zmiennych podzbioru args. Aby sprawdzić, czy zmienna jest ustawiona, czy nie, zakładając, że użyto 'action = "store_true" ...

if args.argument_name:
   # do something
else:
   # do something else
vatsa287
źródło