Potrzebny prosty przykładowy argument: 1 argument, 3 wyniki

529

Dokumentacja dla argparse moduł Pythona , podczas gdy doskonała Jestem pewien, jest zbyt dużo dla mój malutki Początkujący mózg do uchwycenia chwili. Nie muszę robić matematyki w wierszu poleceń ani mieszać się z formatowaniem linii na ekranie ani zmieniać znaków opcji. Wszystko, co chcę zrobić, to „Jeśli arg to A, zrób to, jeśli B to zrób, jeśli żadne z powyższych nie pokaże pomocy i wyjdź” .

matowe wilkie
źródło
15
następnie po prostu sprawdź sys.argvargument, który chcesz ...
JBernardo
10
Kiedykolwiek próbował PLAC ? Jest to łatwe w użyciu opakowanie na argparse ze świetną dokumentacją .
kirbyfan64sos,
157
to nie ty. to jest arsenał. próbuje zabrać cię w podróż do gwiazd i nie obchodzi cię, dokąd zmierzałeś.
Florian Heigl
11
Ponownie zwariowane API „pytoniczne”: /
mlvljr,
69
Na zdrowie błogosławi matkie wilkie, za to, że w obronie małych początkujących mózgów jesteś wszędzie.
polka

Odpowiedzi:

255

Moje rozumienie pierwotnego pytania jest dwojakie. Po pierwsze, jeśli chodzi o najprostszy możliwy przykładowy argument, jestem zaskoczony, że go tutaj nie widziałem. Oczywiście, aby być śmiertelnie prostym, wszystko to jest również kosztowne z niewielką mocą, ale może zacząć.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("a")
args = parser.parse_args()

if args.a == 'magic.name':
    print 'You nailed it!'

Ale ten argument pozycyjny jest teraz wymagany. Jeśli pominiesz to podczas wywoływania tego programu, pojawi się błąd dotyczący brakujących argumentów. To prowadzi mnie do drugiej części pierwotnego pytania. Wydaje się, że Matt Wilkie chce pojedynczego opcjonalnego argumentu bez nazwanej etykiety (etykiety opcji). Moją sugestią byłoby zmodyfikowanie powyższego kodu w następujący sposób:

...
parser.add_argument("a", nargs='?', default="check_string_for_empty")
...
if args.a == 'check_string_for_empty':
    print 'I can tell that no argument was given and I can deal with that here.'
elif args.a == 'magic.name':
    print 'You nailed it!'
else:
    print args.a

Może być bardziej eleganckie rozwiązanie, ale działa i jest minimalistyczne.

mightypile
źródło
4
Po pewnym czasie zastanawiam się, że to pytanie w rzeczywistości najlepiej odpowiada pytaniu Q i kłopotom, w jakich byłem w tym czasie. Inne doskonałe odpowiedzi zebrały więcej niż wystarczającą liczbę przedstawicieli, aby udowodnić swoją wartość i mogą wytrzymać niewielką konkurencję. :-)
matt wilkie
@badnack: Cokolwiek chcesz, cokolwiek oznacza „a”. Jeśli oczekujesz jednego argumentu, na przykład nazwy pliku, jest to nazwa wprowadzona jako nazwa pliku w wierszu polecenia. Następnie możesz wykonać własne przetwarzanie, aby ustalić, czy istnieje ono w systemie plików, ale to kolejne pytanie i odpowiedzi.
mightypile
363

Oto sposób, w jaki to robię argparse(z wieloma argumentami):

parser = argparse.ArgumentParser(description='Description of your program')
parser.add_argument('-f','--foo', help='Description for foo argument', required=True)
parser.add_argument('-b','--bar', help='Description for bar argument', required=True)
args = vars(parser.parse_args())

args będzie słownikiem zawierającym argumenty:

if args['foo'] == 'Hello':
    # code here

if args['bar'] == 'World':
    # code here

W twoim przypadku wystarczy dodać tylko jeden argument.

Diego Navarro
źródło
3
jak wspomniano w moim komentarzu do drugiej odpowiedzi, chciałbym zachować automatyczne formatowanie pomocy argparse, ale wydaje się, że nie ma opcji, aby mieć nieokreślony argument (bardziej prawdopodobne, że go nie rozumiem, kiedy go widzę ), np. trzeba to zrobić foo.py --action installlub foo.py --action removezamiast tego po prostufoo.py install
matt wilkie
7
@mattwilkie Następnie musisz zdefiniować argument pozycyjny w ten sposób: parser.add_argument('install', help='Install the app') (Zauważ, że nie możesz zdefiniować argumentu pozycyjnego za pomocą required=True)
Diego Navarro
32
Odpowiedź na to pytanie bardzo pomogła, ponieważ nie wiedziałem, gdzie znaleźć opcje po ich przekazaniu . Innymi słowy, musiałem zrozumieć, w jaki sposób argswygenerowano ten dykt, jak powyżej.
mrKelley,
3
Użyj „krótkiej formy”, gdy wywołujesz program bezpośrednio z wiersza poleceń, i „długiej formy”, gdy uruchamiasz program / polecenie w skrypcie. W takim przypadku jest bardziej czytelny dla człowieka dzięki długiej formie, a zatem łatwiej jest podążać za logiką kodu / skryptu.
ola
17
Osobiście uważam, że łatwiej jest uzyskać dostęp do argumentów jako args.fooi args.barzamiast składni słownika. Oba sposoby są oczywiście w porządku, ale args nie jest tak naprawdę słownikiem, ale argparse.Namespaceobiektem.
Michael Mior
210

argparseDokumentacja jest dość dobre, ale pomija kilka przydatnych informacji, które mogą nie być oczywiste. (@Diego Navarro już o tym wspomniał, ale postaram się nieco rozwinąć jego odpowiedź). Podstawowe użycie jest następujące:

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--my-foo', default='foobar')
parser.add_argument('-b', '--bar-value', default=3.14)
args = parser.parse_args()

Obiekt, z którego wracasz, parse_args()to obiekt „Przestrzeń nazw”: Obiekt, którego zmienne składowe są nazwane na podstawie argumentów wiersza poleceń. NamespaceCelem jest jak masz dostęp do swoich argumentów i wartości związanych z nimi:

args = parser.parse_args()
print args.my_foo
print args.bar_value

(Zauważ, że argparsezastępuje „-” w nazwach argumentów podkreśleniami podczas nazywania zmiennych).

W wielu sytuacjach możesz chcieć użyć argumentów po prostu jako flag, które nie przyjmują żadnej wartości. Możesz dodać te w argparse w następujący sposób:

parser.add_argument('--foo', action='store_true')
parser.add_argument('--no-foo', action='store_false')

Powyższe spowoduje utworzenie zmiennych o nazwach odpowiednio „foo” o wartości True i „no_foo” o wartości False:

if (args.foo):
    print "foo is true"

if (args.no_foo is False):
    print "nofoo is false"

Pamiętaj również, że możesz dodać opcję „wymagane” podczas dodawania argumentu:

parser.add_argument('-o', '--output', required=True)

W ten sposób, jeśli pominiesz ten argument w wierszu poleceń argparse, powie ci, że go brakuje i zatrzymasz wykonywanie skryptu.

Na koniec zauważ, że możliwe jest stworzenie struktury dyktowania twoich argumentów za pomocą varsfunkcji, jeśli to ułatwi ci życie.

args = parser.parse_args()
argsdict = vars(args)
print argsdict['my_foo']
print argsdict['bar_value']

Jak widać, varszwraca dykton z nazwami argumentów jako kluczami i ich wartościami jako, er, wartości.

Istnieje wiele innych opcji i rzeczy, które możesz zrobić, ale powinno to obejmować najważniejsze, najczęstsze scenariusze użycia.

DMH
źródło
3
Jaki jest sens '-f'i '-b'? Dlaczego nie możesz tego pominąć?
user2763361
13
Dość konwencjonalna jest zarówno wersja „krótka” (jedna kreska), jak i „długa forma” (dwie kreski) dla każdej opcji środowiska wykonawczego. Zobaczysz to na przykład w prawie każdym standardowym narzędziu Unix / Linux; zrób a man cplub man lsprzekonasz się, że wiele opcji występuje w obu smakach (np -f, --force.). Prawdopodobnie istnieją bardzo różne powody, dla których ludzie wolą jedno lub drugie, ale w każdym razie dość standardowe jest udostępnianie obu formularzy w twoim programie.
DMH
59

Matt pyta o parametry pozycyjne w argparse i zgadzam się, że brakuje dokumentacji Pythona w tym aspekcie. Nie ma jednego kompletnego przykładu na nieparzystych stronach ~ 20, które pokazują zarówno analizę, jak i użycie parametrów pozycyjnych .

Żadna z pozostałych odpowiedzi tutaj nie pokazuje pełnego przykładu parametrów pozycyjnych, więc oto kompletny przykład:

# tested with python 2.7.1
import argparse

parser = argparse.ArgumentParser(description="An argparse example")

parser.add_argument('action', help='The action to take (e.g. install, remove, etc.)')
parser.add_argument('foo-bar', help='Hyphens are cumbersome in positional arguments')

args = parser.parse_args()

if args.action == "install":
    print("You asked for installation")
else:
    print("You asked for something other than installation")

# The following do not work:
# print(args.foo-bar)
# print(args.foo_bar)

# But this works:
print(getattr(args, 'foo-bar'))

Rzeczą, która mnie odrzuciła, jest to, że argparse przekształci nazwany argument „--foo-bar” na „foo_bar”, ale parametr pozycyjny o nazwie „foo-bar” pozostanie jako „foo-bar”, dzięki czemu mniej oczywiste jest, jak użyj go w swoim programie.

Zwróć uwagę na dwie linie na końcu mojego przykładu - żaden z nich nie będzie działał, aby uzyskać wartość parametru pozycyjnego foo-bar. Pierwszy jest oczywiście błędny (jest to wyrażenie arytmetyczne args.foo minus pasek), ale drugi też nie działa:

AttributeError: 'Namespace' object has no attribute 'foo_bar'

Jeśli chcesz użyć tego foo-baratrybutu, musisz go użyć getattr, jak widać w ostatnim wierszu mojego przykładu. Dziwne jest to, że jeśli spróbujesz dest=foo_barzmienić nazwę właściwości na coś, co jest łatwiej dostępne, otrzymasz naprawdę dziwny komunikat o błędzie:

ValueError: dest supplied twice for positional argument

Oto jak działa powyższy przykład:

$ python test.py
usage: test.py [-h] action foo-bar
test.py: error: too few arguments

$ python test.py -h
usage: test.py [-h] action foo-bar

An argparse example

positional arguments:
  action      The action to take (e.g. install, remove, etc.)
  foo-bar     Hyphens are cumbersome in positional arguments

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

$ python test.py install foo
You asked for installation
foo
Mark E. Haase
źródło
5
nargs='?'Jest to zaklęcie dla „opcjonalnym pozycyjnych” zgodnie stackoverflow.com/questions/4480075/...
Markhu
Fakt, że pozycja foo-barnie jest przekształcana, foo_barjest opisany w bugs.python.org/issue15125 .
hpaulj
2
Myślę, że łatwiejszym obejściem tego błędu jest po prostu wywołanie argumentu „foo_bar” zamiast „foo-bar”, a następnie print args.foo_bardziała. Ponieważ jest to argument pozycyjny, nie musisz określać nazwy podczas wywoływania skryptu, więc nie ma to znaczenia dla użytkownika.
luator
@luator Masz rację, łatwo zmienić nazwę argumentu, ale autor raportu o błędzie dobrze uzasadnia, że ​​nadal jest to błąd ze względu na niepotrzebne obciążenie poznawcze. Używając argparse, należy zatrzymać i przywołać różne konwencje nazewnictwa dla opcji i argumentów. Zobacz bugs.python.org/msg164968 .
Mark E. Haase,
1
@mehaase Całkowicie zgadzam się, że jest to błąd, który należy naprawić. Po prostu myślę, że zmiana nazwy argumentu jest łatwiejszym i mniej mylącym obejściem niż konieczność używania getattr(jest również bardziej elastyczna, ponieważ umożliwia zmianę argumentu z opcjonalnego na pozycyjny bez konieczności zmiany kodu, który używa wartości).
luator
22

Jeszcze jedno wprowadzenie podsumowujące, zainspirowane tym postem .

import argparse

# define functions, classes, etc.

# executes when your script is called from the command-line
if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    #
    # define each option with: parser.add_argument
    #
    args = parser.parse_args() # automatically looks at sys.argv
    #
    # access results with: args.argumentName
    #

Argumenty są definiowane za pomocą kombinacji następujących elementów:

parser.add_argument( 'name', options... )              # positional argument
parser.add_argument( '-x', options... )                # single-char flag
parser.add_argument( '-x', '--long-name', options... ) # flag with long name

Typowe opcje to:

  • help : opis tego argumentu, gdy --helpjest używany.
  • default : wartość domyślna, jeśli argument jest pominięty.
  • wpisz : jeśli oczekujesz a floatlub int(inaczej jest str).
  • dest : nadaj flagę inną nazwę (np '-x', '--long-name', dest='longName'.).
    Uwaga: domyślnie--long-name można uzyskać dostęp za pomocąargs.long_name
  • akcja : dla specjalnego postępowania z niektórymi argumentami
    • store_true, store_false: dla argumentów logicznych
      '--foo', action='store_true' => args.foo == True
    • store_const: do użycia z opcjąconst
      '--foo', action='store_const', const=42 => args.foo == 42
    • count: dla powtarzających się opcji, jak w./myscript.py -vv
      '-v', action='count' => args.v == 2
    • append: dla powtarzających się opcji, jak w./myscript.py --foo 1 --foo 2
      '--foo', action='append' => args.foo == ['1', '2']
  • wymagany : jeśli flaga jest wymagana lub argument pozycyjny nie jest wymagany.
  • nargs : dla flagi do przechwytywania N argumentów
    ./myscript.py --foo a b => args.foo = ['a', 'b']
  • opcje : w celu ograniczenia możliwych danych wejściowych (określ jako listę ciągów znaków lub ints jeśli type=int).
Jonathan H.
źródło
12

Zwróć uwagę na samouczek Argparse w Pythonie HOWTO . Zaczyna się od najbardziej podstawowych przykładów, takich jak ten:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)

i przechodzi do mniej podstawowych.

Istnieje przykład z predefiniowanym wyborem opcji, na przykład pytanie:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
    print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
    print("{}^2 == {}".format(args.square, answer))
else:
    print(answer)
Alexey
źródło
Miło jest widzieć, że dokumenty zostały zaktualizowane. Zapewniam cię, że tak nie było, gdy OP opublikowało pytanie 5 lat temu.
ntwrkguru
10

Oto, co wymyśliłem w moim projekcie edukacyjnym, głównie dzięki @DMH ...

Kod demonstracyjny:

import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f', '--flag', action='store_true', default=False)  # can 'store_false' for no-xxx flags
    parser.add_argument('-r', '--reqd', required=True)
    parser.add_argument('-o', '--opt', default='fallback')
    parser.add_argument('arg', nargs='*') # use '+' for 1 or more args (instead of 0 or more)
    parsed = parser.parse_args()
    # NOTE: args with '-' have it replaced with '_'
    print('Result:',  vars(parsed))
    print('parsed.reqd:', parsed.reqd)

if __name__ == "__main__":
    main()

To mogło ewoluować i jest dostępne online: command-line.py

Skrypt do ćwiczenia tego kodu: Command-line-demo.sh

Peter L.
źródło
2
Na koniec argumentujący przykład, który ma sens
opentokix,
5

Możesz także użyć plac (otoki wokół argparse).

Jako bonus generuje dokładne instrukcje pomocy - patrz poniżej.

Przykładowy skrypt:

#!/usr/bin/env python3
def main(
    arg: ('Argument with two possible values', 'positional', None, None, ['A', 'B'])
):
    """General help for application"""
    if arg == 'A':
        print("Argument has value A")
    elif arg == 'B':
        print("Argument has value B")

if __name__ == '__main__':
    import plac
    plac.call(main)

Przykładowe dane wyjściowe:

Nie podano argumentów - example.py :

usage: example.py [-h] {A,B}
example.py: error: the following arguments are required: arg

Podano nieoczekiwany argument - example.py C :

usage: example.py [-h] {A,B}
example.py: error: argument arg: invalid choice: 'C' (choose from 'A', 'B')

Podano poprawny argument - example.py A :

Argument has value A

Pełne menu pomocy (generowane automatycznie) - example.py -h :

usage: example.py [-h] {A,B}

General help for application

positional arguments:
  {A,B}       Argument with two possible values

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

Krótkie wyjaśnienie:

Nazwa argumentu zwykle jest równa nazwie parametru ( arg).

Adnotacja krotkowa po argparametrze ma następujące znaczenie:

  • Opis ( Argument with two possible values)
  • Rodzaj argumentu - jeden z „flag”, „opcja” lub „pozycyjny” ( positional)
  • Skrót ( None)
  • Rodzaj wartości argumentu - np. float, string ( None)
  • Ograniczony zestaw opcji ( ['A', 'B'])

Dokumentacja:

Aby dowiedzieć się więcej o korzystaniu z plac, sprawdź jego świetną dokumentację:

Plac: Łatwa analiza linii poleceń

quasoft
źródło
4

Aby dodać do tego, co stwierdzili inni:

Zwykle lubię używać parametru „dest”, aby określić nazwę zmiennej, a następnie użyć „globals (). Update ()”, aby umieścić te zmienne w globalnej przestrzeni nazw.

Stosowanie:

$ python script.py -i "Hello, World!"

Kod:

...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints "Hello, World!"
Sandy Chapman
źródło
argparseUżywa wewnętrznie getattri setattrdo uzyskiwania dostępu do wartości w przestrzeni nazw. W ten sposób nie przeszkadzają mu dziwnie sformułowane destwartości.
hpaulj
1

Naprawdę prostym sposobem użycia argparse i zmiany przełączników „-h” / „--help” w celu wyświetlenia własnych instrukcji pomocy dla kodu osobistego jest ustawienie domyślnej pomocy na False, można również dodać tyle dodatkowych .add_arguments, ile chcesz :

import argparse

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('-h', '--help', action='help',
                help='To run this script please provide two arguments')
parser.parse_args()

Uruchom: python test.py -h

Wynik:

usage: test.py [-h]

optional arguments:
  -h, --help  To run this script please provide two arguments
Niecka
źródło
-1

Najprostsza odpowiedź!

PS, ten, który napisał dokument o argparse, jest głupi

kod python:

import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('--o_dct_fname',type=str)
parser.add_argument('--tp',type=str)
parser.add_argument('--new_res_set',type=int)
args = parser.parse_args()
o_dct_fname = args.o_dct_fname
tp = args.tp
new_res_set = args.new_res_set

uruchomiony kod

python produce_result.py --o_dct_fname o_dct --tp father_child --new_res_set 1
gouxute
źródło
Ta odpowiedź nie dodaje niczego nowego / innego niż istniejące odpowiedzi.
NVS Abhilash
jestem najczystszy, rozmowa jest tania, pokaż kod
gouxute