Überprüfen, ob sys.argv [x] definiert ist

Antworten:

64

Am Ende ist der Unterschied zwischen try, exceptund Testen len(sys.argv)nicht allzu bedeutend. Sie sind beide ein bisschen hackisch im Vergleich zu argparse.

Dies fällt mir jedoch ein - als eine Art Low-Budget-Streit:

arg_names = ['command', 'x', 'y', 'operation', 'option']
args = dict(zip(arg_names, sys.argv))

Sie können es sogar verwenden, um ein namedtuplemit Werten zu generieren , die standardmäßig verwendet werden None- alles in vier Zeilen!

Arg_list = collections.namedtuple('Arg_list', arg_names)
args = Arg_list(*(args.get(arg, None) for arg in arg_names))

Falls Sie nicht vertraut sind namedtuple, handelt es sich nur um ein Tupel, das sich wie ein Objekt verhält und es Ihnen ermöglicht, auf seine Werte mithilfe der tup.attributeSyntax anstelle der tup[0]Syntax zuzugreifen .

In der ersten Zeile wird also ein neuer namedtupleTyp mit Werten für jeden der Werte in erstellt arg_names. In der zweiten Zeile werden die Werte aus dem argsWörterbuch übergeben, getum einen Standardwert zurückzugeben, wenn dem angegebenen Argumentnamen kein Wörterwert im Wörterbuch zugeordnet ist.

senderle
quelle
Ich liebe Python immer mehr, alles dank solcher Antworten und natürlich Stack Overflow! Schade, dass wir keine Erklärung für die letzten beiden Zeilen haben. Ich glaube für Anfänger wäre das toll.
Goujon
2
Liebe es! Einfach die beste Lösung, die ich für dieses Problem gesehen habe. Für andere: Es war mir (newb) nicht sofort klar, dass: 1) der 'Befehl' jedes Mal als erstes Argument übergeben wird und 2) Sie Ergebnisse mit args [0] usw. aufrufen können
Matt D
Das ist sicher cool, aber was ist schwierig daran, die Länge zu testen?
Colorlace
1
@ Timwiz Ich sprach nur im Vergleich zu Argparse. Trotzdem trete ich mich heutzutage jedes Mal, wenn ich zu einem alten Drehbuch zurückkehre und feststelle, dass ich kein Argparse verwendet habe.
senderle
116

Überprüfen Sie die Länge von sys.argv:

if len(sys.argv) > 1:
    blah = sys.argv[1]
else:
    blah = 'blah'

Einige Leute bevorzugen den von Ihnen vorgeschlagenen ausnahmebasierten Ansatz (z. B. try: blah = sys.argv[1]; except IndexError: blah = 'blah'), aber ich mag ihn nicht so sehr, weil er nicht annähernd so gut „skaliert“ (z. B. wenn Sie zwei oder drei Argumente akzeptieren möchten). und es kann möglicherweise Fehler verbergen (z. B. wenn Sie einen verwendet blah = foo(sys.argv[1]), aber foo(...)ausgelöst IndexErrorhaben, IndexErrorder ignoriert wird).

David Wolever
quelle
1
Solange Sie jedoch atomar sind, gibt es nichts, worüber Sie sich Sorgen machen müssen try, except. Warten fooSie einfach auf Ihr Argument bis zur elseKlausel.
senderle
3
Sobald Sie über Skalierung nachdenken, ist es Zeit, zu wechseln argparse.
senderle
1
+1 auf Argparse. Ich habe argparse.pyin all meinen Kommandozeilenprojekten.
David Wolever
2
@senderle: klar, wenn du fleißig bist, ist das in Ordnung. Aber meiner Erfahrung nach sind die meisten Programmierer nicht fleißig und setzen die gesamte Logik in die tryKlausel ein. Da es also nicht schwieriger (und meiner Meinung nach etwas hübscher) ist, ziehe ich es vor, nur die Länge zu überprüfen (außerdem vermeiden Sie es, Leute zu haben schreien Sie an, weil Sie Ausnahmen für die Flusskontrolle verwendet haben).
David Wolever
2
@ David, ja, ich verstehe deinen Standpunkt. Ich bin ein bisschen tryentschuldigend, muss ich zugeben. Ich habe nur das Gefühl, dass es manchmal meine Absicht klarer ausdrückt als eine ifAussage.
senderle
22

Eine andere Möglichkeit, die ich noch nicht aufgelistet habe, besteht darin, Ihren Sentinel-Wert im Voraus festzulegen. Diese Methode nutzt die verzögerte Auswertung von Python, bei der Sie nicht immer eine elseAnweisung angeben müssen. Beispiel:

startingpoint = 'blah'
if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]

Oder wenn Sie die Syntax CRAZY verwenden, können Sie den ternären Operator von Python verwenden :

startingpoint = sys.argv[1] if len(sys.argv) >= 2 else 'blah'
Nathanismus
quelle
1
Die Antwort des ternären Operators ist für mich die schönste. Ich sitze hier und verfluche leise die Tatsache, dass ein Teil der von mir gepflegten Software an Python 2.4 gebunden ist, das es nicht hat.
Richard Barrell
11

Ich benutze das - es scheitert nie:

startingpoint = 'blah'
if sys.argv[1:]:
   startingpoint = sys.argv[1]
anatoly techtonik
quelle
Das ist nicht zu überprüfen, ob definiert. Ist eher wie definieren, ob existiert, was nicht dasselbe ist. Ich habe diese Methode auch verwendet, um Fallback-Variablen zu bewerten, bin aber keine Antwort auf die aktuelle Frage.
m3nda
@ erm3nda Ich kann eine startingpointVariable aus dem Beispiel entfernen , aber die Frage ist, eine Fallback-Variable zuzuweisen , also habe ich das gleiche gemacht.
Anatoly Techtonik
1
Wenn Sie es entfernen, erhalten Sie eine Fehlermeldung zu einer nicht definierten Variablen. Ich habe die Frage noch einmal gelesen und was er erwartet ist das, ein variabler Ersatz :) also ist es ok. Vielen Dank für den Rat dieses kurzen Weges, wenn sys.argv[1:]:. Dies funktioniert mit Positionsargumenten, die Anzahl jedoch nicht.
m3nda
10

Es ist eine gewöhnliche Python-Liste. Die Ausnahme, die Sie dafür abfangen würden, ist IndexError, aber Sie sollten stattdessen nur die Länge überprüfen.

if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]
else:
  startingpoint = 'blah'
Richard Barrell
quelle
2

Eine Lösung, die mit der in die Karte integrierten Funktion funktioniert!

arg_names = ['command' ,'operation', 'parameter']
args = map(None, arg_names, sys.argv)
args = {k:v for (k,v) in args}

Dann müssen Sie nur noch Ihre Parameter wie folgt aufrufen:

if args['operation'] == "division":
    if not args['parameter']:
        ...
    if args['parameter'] == "euclidian":
        ...
Guillaume Hillion
quelle
1

Sie können einfach den Wert von argv [1] an argv anhängen und dann prüfen, ob argv [1] nicht der von Ihnen eingegebenen Zeichenfolge entspricht. Beispiel:

from sys import argv
argv.append('SomeString')
if argv[1]!="SomeString":
            print(argv[1])
Hassan Abdul-Kareem
quelle
Für diejenigen, die mich abgelehnt haben, schäme dich, dass du den Fehler nicht geklärt hast.
Hassan Abdul-Kareem
Ich denke, das liegt daran, dass es hackisch ist. Was ist, wenn jemand SomeString als Argument übergibt? Wie kann man das verwenden, wenn man 1 bis 5 Argumente akzeptieren kann?
pbogut
Cool (aber immer noch hackisch) zum Festlegen eines Standardwerts, falls der Benutzer das Argument nicht angibt. Einfach anhängen und dann argv [1] verwenden.
Felizett
1

Ziemlich nah an dem, was der Urheber versucht hat. Hier ist eine Funktion, die ich benutze:

def get_arg(index):
    try:
        sys.argv[index]
    except IndexError:
        return ''
    else:
        return sys.argv[index]

Eine Verwendung wäre also ungefähr so:

if __name__ == "__main__":
    banner(get_arg(1),get_arg(2))
J. Barber
quelle