Einfaches Argparse-Beispiel gesucht: 1 Argument, 3 Ergebnisse

529

Die Dokumentation für das Argparse-Python-Modul ist zwar ausgezeichnet, aber sicher zu viel, als dass mein kleines Anfängerhirn sie jetzt verstehen könnte . Ich muss nicht in der Befehlszeile rechnen oder mich in Formatierungszeilen auf dem Bildschirm einmischen oder Optionszeichen ändern. Alles, was ich tun möchte, ist "Wenn arg A ist, mach das, wenn B das macht, wenn keiner der oben genannten Hilfe zeigt und beende" .

matt wilkie
quelle
15
dann sys.argv
suchen
10
Schon mal Plac ausprobiert ? Es ist ein einfach zu verwendender Wrapper über Argparse mit großartiger Dokumentation .
kirbyfan64sos
157
Du bist es nicht. Es ist Argparse. Es versucht dich auf eine Reise zu den Sternen mitzunehmen und es ist dir egal, wohin du unterwegs bist.
Florian Heigl
11
Wieder verrückte "pythonische" APIs: /
mlvljr
69
Segne dich, Matt Wilkie, dafür, dass du überall für winzige Anfängergehirne eintrittst.
Polka

Antworten:

255

Mein Verständnis der ursprünglichen Frage ist zweifach. Erstens bin ich in Bezug auf das einfachste mögliche Argparse-Beispiel überrascht, dass ich es hier nicht gesehen habe. Um ganz einfach zu sein, es ist natürlich auch alles Overhead mit wenig Strom, aber es könnte Ihnen den Einstieg erleichtern.

import argparse

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

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

Aber dieses Positionsargument ist jetzt erforderlich. Wenn Sie es beim Aufrufen dieses Programms weglassen, wird eine Fehlermeldung bezüglich fehlender Argumente angezeigt. Dies führt mich zum zweiten Teil der ursprünglichen Frage. Matt Wilkie scheint ein einzelnes optionales Argument ohne ein benanntes Label (die --option-Labels) zu wollen. Mein Vorschlag wäre, den obigen Code wie folgt zu ändern:

...
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

Es mag eine elegantere Lösung geben, aber diese funktioniert und ist minimalistisch.

mächtig
quelle
4
Nach einiger Zeit des Nachdenkens schließe ich, dass diese Frage das am besten gestellte Q und die Situation, in der ich mich zu der Zeit befand, am besten beantwortet. Die anderen hervorragenden Antworten haben mehr als genug Wiederholungen gesammelt, um ihren Wert zu beweisen, und können ein wenig Konkurrenz aushalten. :-)
Matt Wilkie
@badnack: Es ist was immer du willst, was auch immer 'a' darstellt. Wenn Sie ein Argument erwarten, beispielsweise einen Dateinamen, wurde dieser als Dateiname in die Befehlszeile eingegeben. Sie können dann Ihre eigene Verarbeitung durchführen, um festzustellen, ob es im Dateisystem vorhanden ist. Dies ist jedoch eine weitere Frage und Antwort.
Mightypile
363

So mache ich das argparse(mit mehreren Argumenten):

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 wird ein Wörterbuch sein, das die Argumente enthält:

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

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

In Ihrem Fall fügen Sie einfach nur ein Argument hinzu.

Diego Navarro
quelle
3
Wie in meinem Kommentar zur anderen Antwort erwähnt, möchte ich die automatische Hilfeformatierung von argparse beibehalten, aber es scheint keine Option für ein unbenanntes Argument zu geben (wahrscheinlicher verstehe ich es einfach nicht, wenn ich es sehe ), zB muss man tun foo.py --action installoder foo.py --action removestatt einfachfoo.py install
matt wilkie
7
@ Mattwilkie Dann müssen Sie ein Positionsargument wie folgt definieren: parser.add_argument('install', help='Install the app') (Beachten Sie, dass Sie kein Positionsargument mit definieren können required=True)
Diego Navarro
32
Diese Antwort hat mir sehr geholfen, da ich nicht wusste, wo ich die Optionen finden sollte, nachdem sie bestanden wurden . Mit anderen Worten, ich musste verstehen, wie das argsDiktat wie oben erzeugt wurde.
MrKelley
3
Verwenden Sie die Kurzform, wenn Sie ein Programm direkt über die Befehlszeile aufrufen, und die Langform, wenn Sie ein Programm / einen Befehl in einem Skript ausführen. In diesem Fall ist es mit der langen Form besser lesbar und somit einfacher, der Logik des Codes / Skripts zu folgen.
Ola
17
Persönlich finde ich es sauberer, auf Argumente als args.foound args.baranstelle der Wörterbuchsyntax zuzugreifen . In beiden Fällen ist das natürlich in Ordnung, aber args ist eigentlich kein Wörterbuch, sondern ein argparse.NamespaceObjekt.
Michael Mior
210

Die argparseDokumentation ist recht gut, lässt jedoch einige nützliche Details aus, die möglicherweise nicht offensichtlich sind. (@Diego Navarro hat bereits einige davon erwähnt, aber ich werde versuchen, seine Antwort leicht zu erweitern.) Die grundlegende Verwendung ist wie folgt:

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

Das Objekt, von dem Sie zurückkehren, parse_args()ist ein 'Namespace'-Objekt: Ein Objekt, dessen Mitgliedsvariablen nach Ihren Befehlszeilenargumenten benannt sind. Das NamespaceObjekt ist, wie Sie auf Ihre Argumente und die damit verbundenen Werte zugreifen:

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

(Beachten Sie, dass argparsebeim Benennen der Variablen '-' in Ihren Argumentnamen durch Unterstriche ersetzt wird.)

In vielen Situationen möchten Sie Argumente möglicherweise einfach als Flags verwenden, die keinen Wert annehmen. Sie können diese in argparse wie folgt hinzufügen:

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

Mit dem obigen Befehl werden Variablen mit dem Namen 'foo' mit dem Wert True bzw. 'no_foo' mit dem Wert False erstellt:

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

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

Beachten Sie auch, dass Sie die Option "Erforderlich" verwenden können, wenn Sie ein Argument hinzufügen:

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

Wenn Sie dieses Argument in der Befehlszeile weglassen, werden Sie auf diese Weise darauf hingewiesen argparse, dass es fehlt, und die Ausführung Ihres Skripts gestoppt.

Beachten Sie schließlich, dass es möglich ist, mithilfe der varsFunktion eine Diktatstruktur Ihrer Argumente zu erstellen , wenn dies Ihnen das Leben erleichtert.

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

Wie Sie sehen können, wird varsein Diktat mit Ihren Argumentnamen als Schlüssel und deren Werten als ähm Werte zurückgegeben.

Es gibt viele andere Optionen und Dinge, die Sie tun können, aber dies sollte die wichtigsten, häufigsten Verwendungsszenarien abdecken.

DMH
quelle
3
Was ist der Sinn des '-f'und '-b'? Warum kannst du das nicht weglassen?
user2763361
13
Es ist ziemlich konventionell, für jede Laufzeitoption sowohl eine Kurzform (ein Bindestrich) als auch eine Langform (zwei Striche) zu haben. Sie werden dies beispielsweise in fast jedem Standard-Unix / Linux-Dienstprogramm sehen. Wenn Sie ein man cpoder tun, werden man lsSie feststellen, dass viele Optionen in beiden Geschmacksrichtungen erhältlich sind (z -f, --force. B. ). Es gibt wahrscheinlich sehr unterschiedliche Gründe, warum die Leute das eine oder andere bevorzugen, aber auf jeden Fall ist es ziemlich normal, beide Formulare in Ihrem Programm verfügbar zu machen.
DMH
59

Matt fragt nach Positionsparametern in Argparse, und ich stimme zu, dass die Python-Dokumentation zu diesem Aspekt fehlt. Es gibt kein einziges vollständiges Beispiel auf den ~ 20 ungeraden Seiten, das sowohl das Parsen als auch die Verwendung von Positionsparametern zeigt .

Keine der anderen Antworten hier zeigt auch ein vollständiges Beispiel für Positionsparameter. Hier ist ein vollständiges Beispiel:

# 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'))

Das, was mich abschreckte, war, dass argparse das benannte Argument "--foo-bar" in "foo_bar" konvertiert, aber ein Positionsparameter namens "foo-bar" bleibt als "foo-bar", was es weniger offensichtlich macht, wie Verwenden Sie es in Ihrem Programm.

Beachten Sie die beiden Zeilen am Ende meines Beispiels - keine dieser Zeilen funktioniert, um den Wert des Positionsparameters für die Balkenleiste zu ermitteln. Der erste ist offensichtlich falsch (es ist ein arithmetischer Ausdruck args.foo minus bar), aber der zweite funktioniert auch nicht:

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

Wenn Sie das foo-barAttribut verwenden möchten , müssen Sie es verwenden getattr, wie in der letzten Zeile meines Beispiels gezeigt. Was verrückt ist, ist, dass wenn Sie versuchen, dest=foo_barden Eigenschaftsnamen in etwas zu ändern, auf das leichter zugegriffen werden kann, eine wirklich bizarre Fehlermeldung angezeigt wird:

ValueError: dest supplied twice for positional argument

So läuft das obige Beispiel ab:

$ 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
quelle
5
nargs='?'ist die Beschwörung für eine "optionale Position" gemäß stackoverflow.com/questions/4480075/…
MarkHu
Die Tatsache, dass eine Position foo-barnicht transformiert wird, foo_barwird in bugs.python.org/issue15125 behandelt .
hpaulj
2
Ich denke, eine einfachere Problemumgehung für diesen Fehler besteht darin, einfach das Argument "foo_bar" anstelle von "foo-bar" aufzurufen und dann zu print args.foo_barfunktionieren. Da es sich um ein Positionsargument handelt, müssen Sie beim Aufrufen des Skripts keinen Namen angeben, sodass dies für den Benutzer keine Rolle spielt.
Luator
@luator Sie haben Recht, es ist einfach, das Argument umzubenennen, aber der Autor des Fehlerberichts macht einen guten Fall geltend, dass dies aufgrund der unnötigen kognitiven Belastung immer noch eine Fehlfunktion ist. Wenn Sie argparse verwenden, müssen Sie die verschiedenen Namenskonventionen für Optionen und Argumente anhalten und aufrufen. Siehe bugs.python.org/msg164968 .
Mark E. Haase
1
@mehaase Ich stimme voll und ganz zu, dass dies eine Fehlfunktion ist, die behoben werden sollte. Ich denke nur, dass das Umbenennen des Arguments die einfachere und weniger verwirrende Problemumgehung ist als die Verwendung getattr(es ist auch flexibler, da Sie ein Argument von optional in positionell ändern können, ohne den Code ändern zu müssen, der den Wert verwendet).
Luator
22

Noch eine zusammenfassende Einführung, inspiriert von diesem Beitrag .

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
    #

Argumente werden mit Kombinationen der folgenden definiert:

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

Allgemeine Optionen sind:

  • Hilfe : Beschreibung für dieses Argument, wenn --helpes verwendet wird.
  • Standard : Standardwert, wenn das Argument weggelassen wird.
  • Typ : Wenn Sie ein floatoder erwarten int(andernfalls str).
  • dest : Geben Sie einer Flagge einen anderen Namen (z '-x', '--long-name', dest='longName'. B. ).
    Hinweis: Standardmäßig --long-namewird mit zugegriffenargs.long_name
  • Aktion : zur besonderen Behandlung bestimmter Argumente
    • store_true, store_false: für boolesche Argumente
      '--foo', action='store_true' => args.foo == True
    • store_const: zur Verwendung mit Optionconst
      '--foo', action='store_const', const=42 => args.foo == 42
    • count: für wiederholte Optionen wie in./myscript.py -vv
      '-v', action='count' => args.v == 2
    • append: für wiederholte Optionen wie in./myscript.py --foo 1 --foo 2
      '--foo', action='append' => args.foo == ['1', '2']
  • Erforderlich : Wenn ein Flag erforderlich ist oder ein Positionsargument nicht.
  • nargs : damit eine Flagge N args erfasst
    ./myscript.py --foo a b => args.foo = ['a', 'b']
  • Auswahlmöglichkeiten : um mögliche Eingaben einzuschränken (als Liste von Zeichenfolgen oder Ints angeben, wenn type=int).
Jonathan H.
quelle
12

Beachten Sie das Argparse-Tutorial in Python-HOWTOs . Es beginnt mit den meisten grundlegenden Beispielen wie diesem:

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)

und geht zu weniger grundlegenden über.

Es gibt ein Beispiel mit vordefinierter Auswahl für eine Option, wie z. B. das, was gefragt wird:

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
quelle
Es ist schön zu sehen, dass die Dokumente aktualisiert wurden. Ich versichere Ihnen, dass dies nicht der Fall war, als OP die Frage vor 5 Jahren stellte.
ntwrkguru
10

Folgendes habe ich mir in meinem Lernprojekt hauptsächlich dank @DMH ausgedacht ...

Demo-Code:

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()

Dies hat sich möglicherweise weiterentwickelt und ist online verfügbar: command-line.py

Skript, um diesen Code zu trainieren : command-line-demo.sh

Peter L.
quelle
2
Endlich ein Argument, das Sinn macht
opentokix
5

Sie können auch plac (einen Wrapper argparse) verwenden.

Als Bonus werden nette Hilfeanweisungen generiert - siehe unten.

Beispielskript:

#!/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)

Beispielausgabe:

Keine Argumente angegeben - example.py :

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

Unerwartetes Argument geliefert - example.py C :

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

Richtiges Argument angegeben - example.py A :

Argument has value A

Vollständiges Hilfemenü (automatisch generiert) - 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

Kurze Erklärung:

Der Name des Arguments entspricht normalerweise dem Parameternamen ( arg).

Die Tupelanmerkung nach dem argParameter hat folgende Bedeutung:

  • Beschreibung ( Argument with two possible values)
  • Art des Arguments - eines von 'flag', 'option' oder 'positional' ( positional)
  • Abkürzung ( None)
  • Art des Argumentwerts - z. float, string ( None)
  • Eingeschränkte Auswahlmöglichkeiten ( ['A', 'B'])

Dokumentation:

Weitere Informationen zur Verwendung von plac finden Sie in der großartigen Dokumentation:

Plac: Analysieren Sie die Befehlszeile auf einfache Weise

Quasoft
quelle
4

Um zu dem hinzuzufügen, was andere gesagt haben:

Normalerweise verwende ich gerne den Parameter 'dest', um einen Variablennamen anzugeben, und verwende dann 'globals (). Update ()', um diese Variablen in den globalen Namespace einzufügen.

Verwendungszweck:

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

Code:

...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints "Hello, World!"
Sandy Chapman
quelle
argparseVerwendet intern getattrund setattrgreift auf Werte im Namespace zu. Auf diese Weise werden seltsam geformte destWerte nicht gestört .
hpaulj
1

Eine wirklich einfache Möglichkeit, argparse zu verwenden und die Schalter '-h' / '--help' zu ändern, um Ihre eigenen Hilfeanweisungen für persönlichen Code anzuzeigen, besteht darin, die Standardhilfe auf False zu setzen. Sie können auch beliebig viele zusätzliche .add_arguments hinzufügen ::

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()

Führen Sie Folgendes aus: python test.py -h

Ausgabe:

usage: test.py [-h]

optional arguments:
  -h, --help  To run this script please provide two arguments
Stall
quelle
-1

Die einfachste Antwort!

PS Derjenige, der das Dokument von Argparse geschrieben hat, ist dumm

Python-Code:

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

Code ausführen

python produce_result.py --o_dct_fname o_dct --tp father_child --new_res_set 1
Gouxute
quelle
Diese Antwort fügt nichts Neues / Anderes als vorhandene Antworten hinzu.
NVS Abhilash
Ich bin am klarsten, sprechen ist billig, zeigen Sie den Code
Gouxute