Frage

Was ist das? am einfachsten, am besten, und die meisten flexibel Methode oder Bibliothek zum Parsen von Python-Befehlszeilenargumenten?

War es hilfreich?

Lösung

Diese Antwort legt nahe optparse was für ältere Python-Versionen geeignet ist.Für Python 2.7 und höher: argparse ersetzt optparse.Sehen diese Antwort für mehr Informationen.

Wie andere Leute bereits betont haben, ist es besser, sich für optparse statt für getopt zu entscheiden.getopt ist so ziemlich eine Eins-zu-eins-Zuordnung der Standardfunktionen der getopt(3)-C-Bibliothek und nicht sehr einfach zu verwenden.

optparse ist zwar etwas ausführlicher, aber viel besser strukturiert und lässt sich später einfacher erweitern.

Hier ist eine typische Zeile zum Hinzufügen einer Option zu Ihrem Parser:

parser.add_option('-q', '--query',
            action="store", dest="query",
            help="query string", default="spam")

Es spricht so ziemlich für sich;Zur Verarbeitungszeit akzeptiert es -q oder --query als Optionen, speichert das Argument in einem Attribut namens query und hat einen Standardwert, wenn Sie ihn nicht angeben.Es ist außerdem selbstdokumentierend, da Sie das Hilfeargument (das bei der Ausführung mit -h/--help verwendet wird) direkt dort mit der Option deklarieren.

Normalerweise analysieren Sie Ihre Argumente mit:

options, args = parser.parse_args()

Dadurch werden standardmäßig die an das Skript übergebenen Standardargumente analysiert (sys.argv[1:]).

options.query wird dann auf den Wert gesetzt, den Sie an das Skript übergeben haben.

Sie erstellen einen Parser einfach dadurch

parser = optparse.OptionParser()

Das sind alle Grundlagen, die Sie brauchen.Hier ist ein vollständiges Python-Skript, das dies zeigt:

import optparse

parser = optparse.OptionParser()

parser.add_option('-q', '--query',
    action="store", dest="query",
    help="query string", default="spam")

options, args = parser.parse_args()

print 'Query string:', options.query

5 Python-Zeilen, die Ihnen die Grundlagen zeigen.

Speichern Sie es in „sample.py“ und führen Sie es einmal mit aus

python sample.py

und einmal mit

python sample.py --query myquery

Darüber hinaus werden Sie feststellen, dass optparse sehr einfach zu erweitern ist.In einem meiner Projekte habe ich eine Command-Klasse erstellt, mit der Sie Unterbefehle einfach in einem Befehlsbaum verschachteln können.Es verwendet optparse stark, um Befehle miteinander zu verketten.Es ist nicht etwas, das ich einfach in ein paar Zeilen erklären kann, aber Sie können es gerne tun Stöbern Sie in meinem Repository für die Hauptklasse, sowie eine Klasse, die es verwendet, und die Option Parser

Andere Tipps

Andere Antworten erwähnen das argparse ist der richtige Weg für neues Python, aber geben Sie keine Anwendungsbeispiele an.Der Vollständigkeit halber finden Sie hier eine kurze Zusammenfassung der Verwendung von argparse:

1) Initialisieren

import argparse

# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')

2) Argumente hinzufügen

# Required positional argument
parser.add_argument('pos_arg', type=int,
                    help='A required integer positional argument')

# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
                    help='An optional integer positional argument')

# Optional argument
parser.add_argument('--opt_arg', type=int,
                    help='An optional integer argument')

# Switch
parser.add_argument('--switch', action='store_true',
                    help='A boolean switch')

3) Analysieren

args = parser.parse_args()

4) Zugang

print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)

5) Überprüfen Sie die Werte

if args.pos_arg > 10:
    parser.error("pos_arg cannot be larger than 10")

Verwendung

Richtige Verwendung:

$ ./app 1 2 --opt_arg 3 --switch

Argument values:
1
2
3
True

Falsche Argumente:

$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'

$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10

Vollständige Hilfe:

$ ./app -h

usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]

Optional app description

positional arguments:
  pos_arg            A required integer positional argument
  opt_pos_arg        An optional integer positional argument

optional arguments:
  -h, --help         show this help message and exit
  --opt_arg OPT_ARG  An optional integer argument
  --switch           A boolean switch

Verwendung von docopt

Seit 2012 ist Python sehr einfach, leistungsstark und wirklich Cool Modul zum Parsen von Argumenten aufgerufen docopt.Es funktioniert mit Python 2.6 bis 3.5 und erfordert keine Installation (einfach kopieren).Hier ist ein Beispiel aus der Dokumentation:

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

So, das ist es:2 Zeilen Code plus Ihre Dokumentzeichenfolge Ist wesentlich und Sie erhalten Ihre Argumente analysiert und in Ihrem Argumentobjekt verfügbar.Ich habe dir gesagt, dass es cool ist, nicht wahr ;-)

Python-Fire verwenden

Seit 2017 Python-Feuer hat ein weiteres cooles Modul, das Ihrem Code eine CLI-Schnittstelle geben kann, während Sie dies tun null Argumentanalyse.Hier ist ein einfaches Beispiel aus der Dokumentation (dieses kleine Programm stellt die Funktion bereit double zur Kommandozeile):

import fire

class Calculator(object):

  def double(self, number):
    return 2 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

Von der Befehlszeile aus können Sie Folgendes ausführen:

> calculator.py double 10
20
> calculator.py double --number=15
30

Großartig, nicht wahr?

Der neue hippe Weg ist argparse für diese Gründe dafür.argparse > optparse > getopt

aktualisieren: Ab py2.7 argparse ist Teil der Standardbibliothek und optparse ist veraltet.

ich bevorzuge Klicken.Es abstrahiert Verwaltungsoptionen und ermöglicht „(...) das Erstellen schöner Befehlszeilenschnittstellen auf zusammensetzbare Weise mit so wenig Code wie nötig“.

Hier ist ein Beispiel für die Verwendung:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
              help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

Außerdem werden automatisch gut formatierte Hilfeseiten generiert:

$ python hello.py --help
Usage: hello.py [OPTIONS]

  Simple program that greets NAME for a total of COUNT times.

Options:
  --count INTEGER  Number of greetings.
  --name TEXT      The person to greet.
  --help           Show this message and exit.

So ziemlich jeder nutzt es getopt

Hier ist der Beispielcode für das Dokument:

import getopt, sys

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
    except getopt.GetoptError:
        # print help information and exit:
        usage()
        sys.exit(2)
    output = None
    verbose = False
    for o, a in opts:
        if o == "-v":
            verbose = True
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        if o in ("-o", "--output"):
            output = a

Kurz gesagt, so funktioniert es.

Sie haben zwei Arten von Optionen.Diejenigen, die Argumente erhalten, und diejenigen, die genau wie Schalter sind.

sys.argv ist so ziemlich dein char** argv in C.Wie in C überspringen Sie das erste Element, das der Name Ihres Programms ist, und analysieren nur die Argumente: sys.argv[1:]

Getopt.getopt analysiert es gemäß der Regel, die Sie im Argument angeben.

"ho:v" Hier werden die kurzen Argumente beschrieben: -ONELETTER.Der : bedeutet, dass -o akzeptiert ein Argument.

Endlich ["help", "output="] beschreibt lange Argumente ( --MORETHANONELETTER ).Der = nach der Ausgabe bedeutet wiederum, dass die Ausgabe ein Argument akzeptiert.

Das Ergebnis ist eine Liste von Paaren (Option, Argument)

Wenn eine Option kein Argument akzeptiert (wie --help Hier das arg Teil ist eine leere Zeichenfolge.Normalerweise möchten Sie diese Liste dann in einer Schleife durchlaufen und den Optionsnamen wie im Beispiel testen.

Ich hoffe, das hat Ihnen geholfen.

Verwenden optparse die mit der Standardbibliothek geliefert wird.Zum Beispiel:

#!/usr/bin/env python
import optparse

def main():
  p = optparse.OptionParser()
  p.add_option('--person', '-p', default="world")
  options, arguments = p.parse_args()
  print 'Hello %s' % options.person

if __name__ == '__main__':
  main()

Quelle: Verwenden von Python zum Erstellen von UNIX-Befehlszeilentools

Ab Python 2.7 ist optparse jedoch veraltet, siehe: Warum argparse anstelle von optparse verwenden?

Nur für den Fall, dass Sie es benötigen, kann dies bei Bedarf hilfreich sein greifen Unicode-Argumente unter Win32 (2K, XP usw.):


from ctypes import *

def wmain(argc, argv):
    print argc
    for i in argv:
        print i
    return 0

def startup():
    size = c_int()
    ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
    ref = c_wchar_p * size.value
    raw = ref.from_address(ptr)
    args = [arg for arg in raw]
    windll.kernel32.LocalFree(ptr)
    exit(wmain(len(args), args))
startup()

Leichte Standardeinstellungen für Befehlszeilenargumente

Obwohl argparse ist großartig und die richtige Antwort für vollständig dokumentierte Befehlszeilenschalter und erweiterte Funktionen. Sie können Funktionsargument-Standardeinstellungen verwenden, um unkomplizierte Positionsargumente sehr einfach zu verarbeiten.

import sys

def get_args(name='default', first='a', second=2):
    return first, int(second)

first, second = get_args(*sys.argv)
print first, second

Das Argument „name“ erfasst den Skriptnamen und wird nicht verwendet.Die Testausgabe sieht folgendermaßen aus:

> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20

Für einfache Skripte, bei denen ich nur einige Standardwerte möchte, finde ich das völlig ausreichend.Möglicherweise möchten Sie auch eine Typumwandlung in die Rückgabewerte einschließen, da sonst alle Befehlszeilenwerte Zeichenfolgen sind.

Ich denke, der beste Weg für größere Projekte ist optparse, aber wenn Sie nach einem einfachen Weg suchen, vielleicht http://werkzeug.pocoo.org/documentation/script ist etwas für dich.

from werkzeug import script

# actions go here
def action_foo(name=""):
    """action foo does foo"""
    pass

def action_bar(id=0, title="default title"):
    """action bar does bar"""
    pass

if __name__ == '__main__':
    script.run()

Grundsätzlich ist jede Funktion action_* der Befehlszeile ausgesetzt und eine nette Hilfebotschaft wird kostenlos generiert.

python foo.py 
usage: foo.py <action> [<options>]
       foo.py --help

actions:
  bar:
    action bar does bar

    --id                          integer   0
    --title                       string    default title

  foo:
    action foo does foo

    --name                        string

Ich bevorzuge optparse gegenüber getopt.Es ist sehr deklarativ:Sie teilen ihm die Namen der Optionen und die Auswirkungen mit, die sie haben sollen (z. B. das Festlegen eines booleschen Felds), und es gibt Ihnen ein Wörterbuch zurück, das gemäß Ihren Spezifikationen gefüllt ist.

http://docs.python.org/lib/module-optparse.html

Consoleargs verdient hier Erwähnung.Es ist sehr einfach zu bedienen.Hör zu:

from consoleargs import command

@command
def main(url, name=None):
  """
  :param url: Remote URL 
  :param name: File name
  """
  print """Downloading url '%r' into file '%r'""" % (url, name)

if __name__ == '__main__':
  main()

Jetzt in der Konsole:

% python demo.py --help
Usage: demo.py URL [OPTIONS]

URL:    Remote URL 

Options:
    --name -n   File name

% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'

% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''

Argparse-Code kann länger sein als der tatsächliche Implementierungscode!

Das ist ein Problem, das meiner Meinung nach bei den meisten gängigen Optionen zum Parsen von Argumenten besteht: Wenn Ihre Parameter nur bescheiden sind, wird der Code zu ihrer Dokumentation unverhältnismäßig groß im Vergleich zu dem Nutzen, den sie bieten.

Ein relativer Neuling in der Argument-Parsing-Szene (glaube ich). Ort.

Es macht einige anerkannte Kompromisse mit argparse, verwendet aber Inline-Dokumentation und lässt sich einfach umschließen main() Typ Funktion Funktion:

def main(excel_file_path: "Path to input training file.",
     excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
     existing_model_path: "Path to an existing model to refine."=None,
     batch_size_start: "The smallest size of any minibatch."=10.,
     batch_size_stop:  "The largest size of any minibatch."=250.,
     batch_size_step:  "The step for increase in minibatch size."=1.002,
     batch_test_steps: "Flag.  If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."

    pass # Implementation code goes here!

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

Hier ist eine Methode, keine Bibliothek, die für mich zu funktionieren scheint.

Die Ziele hier sind, prägnant zu sein, jedes Argument wird durch eine einzelne Zeile analysiert, die Argumente werden zur besseren Lesbarkeit ausgerichtet, der Code ist einfach und hängt nicht von irgendwelchen speziellen Modulen ab (nur os + sys), warnt elegant vor fehlenden oder unbekannten Argumenten , verwendet eine einfache for/range()-Schleife und funktioniert in Python 2.x und 3.x

Dargestellt sind zwei Umschaltflags (-d, -v) und zwei durch Argumente gesteuerte Werte (-i xxx und -o xxx).

import os,sys

def HelpAndExit():
    print("<<your help output goes here>>")
    sys.exit(1)

def Fatal(msg):
    sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
    sys.exit(1)

def NextArg(i):
    '''Return the next command line argument (if there is one)'''
    if ((i+1) >= len(sys.argv)):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return(1, sys.argv[i+1])

### MAIN
if __name__=='__main__':

    verbose = 0
    debug   = 0
    infile  = "infile"
    outfile = "outfile"

    # Parse command line
    skip = 0
    for i in range(1, len(sys.argv)):
        if not skip:
            if   sys.argv[i][:2] == "-d": debug ^= 1
            elif sys.argv[i][:2] == "-v": verbose ^= 1
            elif sys.argv[i][:2] == "-i": (skip,infile)  = NextArg(i)
            elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
            elif sys.argv[i][:2] == "-h": HelpAndExit()
            elif sys.argv[i][:1] == "-":  Fatal("'%s' unknown argument" % sys.argv[i])
            else:                         Fatal("'%s' unexpected" % sys.argv[i])
        else: skip = 0

    print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))

Das Ziel von NextArg() besteht darin, das nächste Argument zurückzugeben, während nach fehlenden Daten gesucht wird, und „skip“ überspringt die Schleife, wenn NextArg() verwendet wird, sodass die Flag-Analyse auf einen Zeilen beschränkt bleibt.

Ich habe den Ansatz von Erco erweitert, um erforderliche Positionsargumente und optionale Argumente zu ermöglichen.Diese sollten vor -d, -v usw. stehen.Argumente.

Positions- und optionale Argumente können mit PosArg(i) bzw. OptArg(i, default) abgerufen werden.Wenn ein optionales Argument gefunden wird, wird die Startposition der Suche nach Optionen (z. B.-i) wird um 1 nach vorne verschoben, um einen „unerwarteten“ fatalen Fehler zu vermeiden.

import os,sys


def HelpAndExit():
    print("<<your help output goes here>>")
    sys.exit(1)

def Fatal(msg):
    sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
    sys.exit(1)

def NextArg(i):
    '''Return the next command line argument (if there is one)'''
    if ((i+1) >= len(sys.argv)):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return(1, sys.argv[i+1])

def PosArg(i):
    '''Return positional argument'''
    if i >= len(sys.argv):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return sys.argv[i]

def OptArg(i, default):
    '''Return optional argument (if there is one)'''
    if i >= len(sys.argv):
        Fatal("'%s' expected an argument" % sys.argv[i])
    if sys.argv[i][:1] != '-':
        return True, sys.argv[i]
    else:
        return False, default


### MAIN
if __name__=='__main__':

    verbose = 0
    debug   = 0
    infile  = "infile"
    outfile = "outfile"
    options_start = 3

    # --- Parse two positional parameters ---
    n1 = int(PosArg(1))
    n2 = int(PosArg(2))

    # --- Parse an optional parameters ---
    present, a3 = OptArg(3,50)
    n3 = int(a3)
    options_start += int(present)

    # --- Parse rest of command line ---
    skip = 0
    for i in range(options_start, len(sys.argv)):
        if not skip:
            if   sys.argv[i][:2] == "-d": debug ^= 1
            elif sys.argv[i][:2] == "-v": verbose ^= 1
            elif sys.argv[i][:2] == "-i": (skip,infile)  = NextArg(i)
            elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
            elif sys.argv[i][:2] == "-h": HelpAndExit()
            elif sys.argv[i][:1] == "-":  Fatal("'%s' unknown argument" % sys.argv[i])
            else:                         Fatal("'%s' unexpected" % sys.argv[i])
        else: skip = 0

    print("Number 1 = %d" % n1)
    print("Number 2 = %d" % n2)
    print("Number 3 = %d" % n3)
    print("Debug    = %d" % debug)
    print("verbose  = %d" % verbose)
    print("infile   = %s" % infile)
    print("outfile  = %s" % outfile) 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top