Wie lese / verarbeite ich Befehlszeilenargumente?

623

Ich bin ursprünglich ein C-Programmierer. Ich habe zahlreiche Tricks und "Hacks" gesehen, um viele verschiedene Argumente zu lesen.

Wie können Python-Programmierer dies tun?

verbunden

Martineau
quelle
5
Verwenden Sie docopt (siehe die Antwort von @ ralbatross unter stackoverflow.com/a/14790373/116891 ). Ich habe jeden anderen Weg ausprobiert und wirklich, docopt ist der einzige, den ich in Zukunft verwenden werde.
Pat
2
Ich glaube nicht, dass es einen einzigen besten Weg gibt. argparse ist Standard und nützlich. docopt ist sehr elegant, aber nicht in der Standardbibliothek. Für eine sehr einfache Verwendung können Sie festlegen, dass Funktionsstandardwerte die Standardeinstellungen für Befehlszeilenargumente für Sie verarbeiten .
Simon Hibbs

Antworten:

456

Die kanonische Lösung in der Standardbibliothek lautet argparse( docs ):

Hier ist ein Beispiel:

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="filename",
                    help="write report to FILE", metavar="FILE")
parser.add_argument("-q", "--quiet",
                    action="store_false", dest="verbose", default=True,
                    help="don't print status messages to stdout")

args = parser.parse_args()

argparse unterstützt (unter anderem):

  • Mehrere Optionen in beliebiger Reihenfolge.
  • Kurze und lange Optionen.
  • Standardwerte.
  • Generierung einer Verwendungshilfemeldung.
Ayman Hourieh
quelle
27
Ja, das sind die besten. Da sie Teil der Standardbibliothek sind, können Sie sicher sein, dass sie verfügbar und einfach zu verwenden sind. Insbesondere Optparse ist leistungsstark und einfach.
Barry Wark
4
Optparse ist einer der besten; getopt ist alt und sollte eigentlich als veraltet angesehen werden.
Jemfinch
12
An diesem Punkt (12/2011) wird Argparse jetzt als bessere Option als Optparse angesehen, richtig?
oob
54
In der Python-Dokumentation wird die Verwendung von Argparse anstelle von Optparse vorgeschlagen.
EarthmeLon
7
Da dies optparseveraltet ist, ist der Fragesteller der Frage kein Mitglied mehr im Stapelüberlauf. Dies ist die akzeptierte Antwort auf eine gut sichtbare Frage. Bitte überlegen Sie, Ihren Beispielcode vollständig neu zu schreiben, um argparsestattdessen stdlib zu verwenden.
wim
548
import sys

print("\n".join(sys.argv))

sys.argv ist eine Liste, die alle Argumente enthält, die in der Befehlszeile an das Skript übergeben wurden.

Grundsätzlich,

import sys
print(sys.argv[1:])
John Slavick
quelle
83
Für wirklich einfache Dinge ist dies der richtige Weg, obwohl Sie wahrscheinlich nur verwenden möchten sys.argv[1:](vermeidet den Skriptnamen).
Xiong Chiamiov
128

Ich gehe einfach herum und evangelisiere für Argparse, was aus diesen Gründen besser ist . Im Wesentlichen:

(vom Link kopiert)

  • Das argparse-Modul kann positionelle und optionale Argumente verarbeiten, während optparse nur optionale Argumente verarbeiten kann

  • argparse ist nicht dogmatisch darüber, wie Ihre Befehlszeilenschnittstelle aussehen soll - Optionen wie -file oder / file werden ebenso unterstützt wie erforderliche Optionen. Optparse weigert sich, diese Merkmale zu unterstützen, und zieht Reinheit der Praktikabilität vor

  • argparse erzeugt informativere Verwendungsnachrichten, einschließlich der aus Ihren Argumenten ermittelten Befehlszeilenverwendung, und Hilfemeldungen für Positions- und optionale Argumente. Das optparse-Modul erfordert das Schreiben einer eigenen Verwendungszeichenfolge und kann keine Hilfe für Positionsargumente anzeigen.

  • argparse unterstützt Aktionen, die eine variable Anzahl von Befehlszeilenargumenten verbrauchen, während optparse erfordert, dass die genaue Anzahl von Argumenten (z. B. 1, 2 oder 3) im Voraus bekannt ist

  • argparse unterstützt Parser, die an Unterbefehle senden, während optparse allow_interspersed_argsdas manuelle Festlegen und Ausführen des Parser-Versands erfordert

Und mein persönlicher Favorit:

  • Mit argparse können die Typ- und Aktionsparameter add_argument() mit einfachen aufrufbaren Elementen angegeben werden, während für optparse das Hacken von Klassenattributen wie STORE_ACTIONSoder CHECK_METHODSeine ordnungsgemäße Argumentprüfung erforderlich ist
Silfheed
quelle
27
Dies ist jetzt Teil von Standard Python ab 2.7 und 3.2 :)
jpswain
Was sind "optionale Argumente"? Sie sagen, sie sind in Optparse. Ich dachte, dass es sich um Argumente handelt, die möglicherweise geliefert werden oder nicht, aber Sie sagten, sie seien in Optparse, während Sie weiter sagten, dass "Optparse erfordert, dass die genaue Anzahl der Argumente im Voraus bekannt ist". Entweder unterscheidet sich Ihre Definition von "optionalem Argument" von dem, was ich dachte, oder Ihre Antwort stimmt nicht mit sich selbst überein.
ArtOfWarfare
1
Nur ein Kritikpunkt: Argparse-Dokumentation ist auch wahnsinnig, wahnsinnig kompliziert. Sie können keine einfache Antwort für "Wie kann ich ein Befehlszeilenargument dazu bringen, einen einzelnen Wert aufzunehmen, und wie kann ich auf diesen Wert zugreifen?" Erhalten. </ meckern>
Osman
2
@osman Dieses sanfte Tutorial über Argparse könnte helfen ...
Lebensbalance
2
@ArtOfWarfare "optionale Argumente" bedeuten in diesem Zusammenhang vermutlich Argumente, die mit optionähnlichen Argumenten wie -foder angegeben wurden --foo, während "genaue Anzahl der Argumente im Voraus bekannt sein" vermutlich Positionsargumente ohne vorhergehende Optionsflags bedeutet.
mtraceur
67

Es gibt auch ein argparsestdlib-Modul (eine "Verbesserung" des stdlib- optparseModuls). Beispiel aus der Einführung zu argparse :

# script.py
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'integers', metavar='int', type=int, choices=range(10),
         nargs='+', help='an integer in the range 0..9')
    parser.add_argument(
        '--sum', dest='accumulate', action='store_const', const=sum,
        default=max, help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print(args.accumulate(args.integers))

Verwendungszweck:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10
jfs
quelle
1
Es ist nur ein Kopieren und Einfügen
blitu12345
3
@ blitu12345 Zum Zeitpunkt der Veröffentlichung meiner Antwort gab es keine anderen Antworten, in denen Argparse in irgendeiner Weise erwähnt wurde. Das Modul selbst war nicht in stdlib¶ Was haben Sie gegen Codebeispiele aus der Dokumentation? Warum ist es Ihrer Meinung nach notwendig, eigene Beispiele anstelle von Beispielen des Autors des Moduls zu erstellen? Und ich mag keine Nur-Link-Antworten (ich bin nicht allein).
JFS
1
Die Leute, die hierher kamen, hatten bereits eine Idee, was in der Dokumentation steht, und werden nur zur weiteren Klärung des Themas hier sein. Dasselbe war mein Fall, aber was ich hier wirklich gefunden habe, ist ein Kopieren und Einfügen aus den Originaldokumenten.
blitu12345
2
„Völker kommen hier hatte schon eine Idee , was in der Dokumentation“ - i hoch Zweifel , dass assumtion. irgendwie.
Sjas
49

Eine Möglichkeit ist die Verwendung sys.argv. Dadurch werden der Skriptname als erstes Argument und alle anderen Parameter gedruckt, die Sie an ihn übergeben.

import sys

for arg in sys.argv:
    print arg
JPCosta
quelle
49

Die docopt- Bibliothek ist wirklich schick . Es erstellt ein Argument dikt aus der Verwendungszeichenfolge für Ihre App.

ZB aus der docopt readme:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)
Ralbatross
quelle
4
Dies ist schnell mein Lieblingsweg geworden. Es ist String-Parsing, also etwas spröde, aber alles an einem Ort spröde, und Sie können eine Vorschau Ihrer Logik unter try.docopt.org anzeigen . Optionale und sich gegenseitig ausschließende Argumente werden auf sehr elegante Weise ausgeführt.
Gvoysey
4
Ich bin verzweifelt, den Rest des Codes für naval_fate.py zu sehen
John Lawrence Aspden
48

Wenn Sie etwas schnelles und nicht sehr flexibles brauchen

main.py:

import sys

first_name = sys.argv[1]
last_name = sys.argv[2]
print("Hello " + first_name + " " + last_name)

Dann renne python main.py James Smith

um die folgende Ausgabe zu erzeugen:

Hallo James Smith

Kent Munthe Caspersen
quelle
Eine realistischere Nutzung wäre Für python main.py "James Smith"welchen puts James Smithin sys.argv[1]und erzeugt ein , IndexErrorwenn Sie versuchen , die nicht vorhandene zu verwenden sys.argv[2]. Das Zitierverhalten hängt etwas davon ab, von welcher Plattform und Shell Sie Python ausführen.
Tripleee
10
Ich stimme nicht zu, dass meine Verwendung weniger realistisch ist. Stellen Sie sich vor, Ihr Programm muss den genauen Vor- und Nachnamen einer Person kennen, um das Skript in einem Unternehmen auszuführen, in dem Personen mehrere Vor- und Nachnamen haben können? Wenn James Smith Joseph als zusätzlichen Vor- oder Nachnamen hat, wie würde man dann unterscheiden, ob Joseph ein zusätzlicher Vor- oder Nachname ist, wenn Sie dies nur tun python main.py "James Joseph Smith"? Wenn Sie sich mit Index außerhalb der Grenzen befassen, können Sie die Anzahl der bereitgestellten Argumente überprüfen. Weniger realistisch oder nicht, mein Beispiel zeigt, wie man mit mehreren Argumenten umgeht.
Kent Munthe Caspersen
1
Alle anderen Antworten beziehen sich auf die Planung einer Mondlandemission. Ich benutze nur einfach gmail-trash-msg.py MessageID. Diese Antwort ist direkt an den MessageIDTestparameter übergeben worden sys.argv[1].
WinEunuuchs2Unix
26
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]
whi
quelle
19

Ich benutze selbst optparse, aber ich mag die Richtung, die Simon Willison mit seiner kürzlich eingeführten optfunc- Bibliothek einschlägt . Es funktioniert durch:

"Introspektion einer Funktionsdefinition (einschließlich ihrer Argumente und ihrer Standardwerte) und Verwendung dieser, um einen Befehlszeilenargument-Parser zu erstellen."

So zum Beispiel diese Funktionsdefinition:

def geocode(s, api_key='', geocoder='google', list_geocoders=False):

wird in diesen optparse Hilfetext umgewandelt:

    Options:
      -h, --help            show this help message and exit
      -l, --list-geocoders
      -a API_KEY, --api-key=API_KEY
      -g GEOCODER, --geocoder=GEOCODER
Van Gale
quelle
8

Ich mag getopt von stdlib, zB:

try:
    opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
except getopt.GetoptError, err: 
    usage(err)

for opt, arg in opts:
    if opt in ('-h', '--help'): 
        usage()

if len(args) != 1:
    usage("specify thing...")

In letzter Zeit habe ich etwas Ähnliches verpackt, um die Dinge weniger ausführlich zu machen (z. B. "-h" implizit zu machen).

Peter Ericson
quelle
8

Pocoos Klick ist intuitiver, erfordert weniger Boilerplate und ist mindestens so leistungsfähig wie Argparse.

Die einzige Schwäche, auf die ich bisher gestoßen bin, ist, dass Sie nicht viel anpassen können, um Seiten zu helfen, aber das ist normalerweise keine Voraussetzung, und docopt scheint die klare Wahl zu sein, wenn dies der Fall ist.

Ryne Everett
quelle
7

Wie Sie sehen können, ist optparse "Das optparse-Modul ist veraltet und wird nicht weiterentwickelt. Die Entwicklung wird mit dem argparse- Modul fortgesetzt ."

tverrbjelke
quelle
5
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))

Assuming the Python code above is saved into a file called prog.py
$ python prog.py -h

Ref-link: https://docs.python.org/3.3/library/argparse.html
JON
quelle
4

Vielleicht interessiert Sie ein kleines Python-Modul, das ich geschrieben habe, um die Handhabung von Befehlszeilenargumenten noch einfacher zu machen (Open Source und kostenlos) - Commando

Mufasa
quelle
1
Es gibt bereits ein weiteres Befehlszeilen-Parsing-Modul namens Commando: github.com/lakshmivyas/commando . Es verpackt Argparse mit Dekorateuren.
Roberto Bonvallet
1
Python und Rad Neuerfindung
Derek
4

Ich empfehle einen Blick auf docopt als einfache Alternative zu diesen anderen zu betrachten.

docopt ist ein neues Projekt, bei dem Ihre --help-Verwendungsnachricht analysiert wird, anstatt dass Sie alles selbst implementieren müssen. Sie müssen nur Ihre Nutzungsnachricht in das POSIX-Format stellen.

David C. Bishop
quelle
4

Eine weitere Option ist Argh . Es baut auf Argparse auf und lässt Sie Dinge schreiben wie:

import argh

# declaring:

def echo(text):
    "Returns given word as is."
    return text

def greet(name, greeting='Hello'):
    "Greets the user with given name. The greeting is customizable."
    return greeting + ', ' + name

# assembling:

parser = argh.ArghParser()
parser.add_commands([echo, greet])

# dispatching:

if __name__ == '__main__':
    parser.dispatch()

Es wird automatisch Hilfe usw. generiert, und Sie können Dekorateure verwenden, um zusätzliche Anleitungen zur Funktionsweise des Arg-Parsing zu geben.

kreisförmige Ruine
quelle
Dies ist die beste Lösung. Verwenden arghist einfacher als andere Bibliotheken oder Verwenden sys.
Juanjo Salvador
Ich wollte es mögen, arghaber es ist nicht besonders geeignet für Szenarien, in denen Ihr größter Wunsch darin besteht, keinen Befehl mit Unterbefehlen zu haben.
Tripleee
1
@tripleee YMMV, aber ich stellte fest, dass dies eher ein Fehler in der Dokumentation als in der Bibliothek selbst war. Es scheint durchaus machbar, def frobnicate_spleches(...)eine Funktion zu definieren, die alles tut, was Ihr Skript tut, und dann if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)am Ende der Datei.
kreisförmige Ruine
0

Meine Lösung ist entrypoint2 . Beispiel:

from entrypoint2 import entrypoint
@entrypoint
def add(file, quiet=True): 
    ''' This function writes report.

    :param file: write report to FILE
    :param quiet: don't print status messages to stdout
    '''
    print file,quiet

Hilfstext:

usage: report.py [-h] [-q] [--debug] file

This function writes report.

positional arguments:
  file         write report to FILE

optional arguments:
  -h, --help   show this help message and exit
  -q, --quiet  don't print status messages to stdout
  --debug      set logging level to DEBUG
Ponty
quelle