it-swarm.com.de

Python: Verwenden von sys.exit oder SystemExit, Unterschiede und Vorschläge

Online lesen einige Programmierer verwenden sys.exit, andere verwenden SystemExit.
Entschuldigung für die grundlegende Frage:

  1. Was ist der Unterschied?
  2. Wann muss ich SystemExit oder sys.exit in einer Funktion verwenden?

Beispiel

ref = osgeo.ogr.Open(reference)
if ref is None:
    raise SystemExit('Unable to open %s' % reference)

oder

ref = osgeo.ogr.Open(reference)
if ref is None:
    print('Unable to open %s' % reference)
    sys.exit(-1)
35
Gianni Spear

Kein praktischer Unterschied, aber es gibt noch einen anderen Unterschied in Ihrem Beispielcode - print geht auf standard out, aber der Ausnahmetext geht auf standard Fehler (was wahrscheinlich das ist, was Sie wollen).

19
RichieHindle

sys.exit(s) ist nur eine Abkürzung für raise SystemExit(s), wie im vorherigen Dokument beschrieben. versuche help(sys.exit). Anstelle eines Ihrer Beispielprogramme können Sie dies tun

sys.exit('Unable to open %s' % reference)
23
Fred Foo

Es gibt 3 Exit-Funktionen, zusätzlich zum Erhöhen von SystemExit.

Der zugrunde liegende Code ist os._exit, der ein int-Argument erfordert, und wird sofort ohne Bereinigung beendet. Es ist unwahrscheinlich, dass Sie diesen jemals berühren möchten, aber er ist da.

sys.exit ist in sysmodule.c definiert und führt einfach PyErr_SetObject(PyExc_SystemExit, exit_code); aus. Dies ist praktisch das Gleiche wie das direkte Anheben von SystemExit. Im Detail ist das Anheben von SystemExit wahrscheinlich schneller, da sys.exit einen LOAD_ATTR und CALL_FUNCTION vs. RAISE_VARARGS-Opcalls erfordert. Außerdem erzeugt raise SystemExit einen etwas kleineren Bytecode (4 Byte weniger), (1 Byte extra, wenn Sie from sys import exit verwenden, da erwartet wird, dass sys.exit keine zurückgibt, also einen zusätzlichen POP_TOP enthält). 

Die letzte Exit-Funktion ist in site.py definiert und in der REPL als exit oder quit aliasiert. Es handelt sich tatsächlich um eine Instanz der Quitter-Klasse (es kann also einen benutzerdefinierten __repr__ geben, ist also wahrscheinlich der langsamste. Außerdem wird sys.stdin geschlossen, bevor SystemExit aufgerufen wird. Daher wird die Verwendung nur in REPL empfohlen. 

Wie SystemExit gehandhabt wird, ruft die VM schließlich os._exit auf, aber vorher werden einige Bereinigungen vorgenommen. Es führt auch atexit._run_exitfuncs() aus, das alle über das Modul atexit registrierten Callbacks ausführt. Der direkte Aufruf von os._exit umgeht den Schritt atexit.

10
Perkins

Meine persönliche Präferenz ist, dass zumindest SystemExit angehoben wird (oder noch besser - eine aussagekräftigere und gut dokumentierte benutzerdefinierte Ausnahme) und dann so nahe wie möglich an der "main" -Funktion gefangen wird, die dann eine letzte Chance haben kann, dies zu erachten ein gültiger Exit oder nicht. Bibliotheken/tief eingebettete Funktionen, die sys.exit haben, sind vom Design her einfach unangenehm. (Im Allgemeinen sollte das Beenden "so hoch wie möglich" sein)

6
Jon Clements

SystemExit ist eine Ausnahme, was im Wesentlichen bedeutet, dass Ihr Programm ein Verhalten hatte, bei dem Sie es stoppen und einen Fehler auslösen möchten. sys.exit ist die Funktion, die Sie zum Beenden Ihres Programms aufrufen können, wobei Sie möglicherweise einen Rückkehrcode an das System übergeben.

EDIT: Sie sind in der Tat dasselbe, der einzige Unterschied liegt in der Logik hinter Ihrem Programm. Eine Ausnahme ist eine Art "unerwünschtes" Verhalten, ob ein Aufruf einer Funktion aus Sicht des Programmierers eher eine "Standard" -Aktion ist.

3
Cynical

Laut der Dokumentation sys.exit(s) ist raise SystemExit(s) effektiv, also ist es so ziemlich das Gleiche.

2
piokuc

Während der Unterschied mit vielen Antworten beantwortet wurde, macht https://mail.python.org/pipermail/python-list/2016-April/707470.html einen interessanten Punkt:

TL; DR: Es ist besser, eine "normale" Ausnahme auszulösen und SystemExit oder sys.exit nur auf den obersten Ebenen eines Skripts zu verwenden.

Ich bin auf Python 2.7 und Linux, ich habe einen einfachen Code-Bedarfsvorschlag, wenn ich Ich könnte sys.exit (1) durch Raise SystemExit ersetzen.

== aktueller Code ==

def main():    
    try:
       create_logdir()
       create_dataset()
       unittest.main()    
     except Exception as e:
       logging.exception(e)
       sys.exit(EXIT_STATUS_ERROR)

if __== '__main__':    main()

== Geänderter Code ==

def main():    
    try:
       create_logdir()
       create_dataset()
       unittest.main()    
    except Exception as e:
       logging.exception(e)
       raise SystemExit

if __== '__main__':    
    main()

Ich bin persönlich gegen beide. Mein bevorzugtes Muster ist wie diese:

  def main(argv):
    try:
      ...
    except Exception as e:
      logging.exception(e)
      return 1

  if __== '__main__':
    sys.exit(main(sys.argv))

Beachten Sie, dass main () wieder eine normale Funktion mit normalem .__ ist. kehrt zurück.

Außerdem würden die meisten von uns die "Ausnahme-Ausnahme" vermeiden und einfach eine Spitze zulassen Level außer Bubble out: Auf diese Weise erhalten Sie einen Stack-Backtrace für Debuggen Ich stimme zu, dass das Protokollieren der Ausnahme verhindert wird und für hässlichere Konsolenausgabe, aber ich denke, es ist ein Gewinn. Und wenn Sie tun wollen Um die Ausnahme zu protokollieren, gibt es immer Folgendes:

versuchen: ... außer Ausnahme als e: logging.exception (e) erziehen

um die Ausnahme in das Protokoll zu schreiben und trotzdem ausblasen zu lassen normalerweise.

Das Problem mit dem Muster "außer Ausnahme" ist, dass es und _ fängt. verstecktEvery Ausnahme, nicht nur die begrenzte Anzahl von bestimmten Ausnahmen, die Sie verstehen.

Schließlich ist es verpönt, eine bloße Exception-Klasse aufzubauen. Im Python 3 Ich glaube, es ist eigentlich verboten, also ist es nicht portierbar sowieso. Aber auch in Python ist es am besten, eine Ausnahme zu geben Instanz, nicht die Klasse:

systemExit erhöhen (1)

  1. Bei allen Funktionen im try-Block wurde die Ausnahmebedingung mit Raise ausgeblasen

    Beispiel für create_logdir () Hier ist die Funktionsdefinition

def create_logdir ():

versuchen: os.makedirs (LOG_DIR) außer OSError als e: sys.stderr.write ("Fehler beim Erstellen des Protokollverzeichnisses ... Beenden !!!") erziehen "Protokolldatei drucken" + korruptes_log zurückgeben

def main (): Versuchen: create_logdir () Ausnahme Ausnahme als e: logging.exception (e) heben Sie SystemExit auf

(a) Falls create_logdir () fehlschlägt, erhalten wir den folgenden Fehler, ist diese Geldstrafe oder muss ich diesen Code verbessern.

Fehler beim Erstellen des Protokollverzeichnisses ... Beenden !!! ERROR: root: [Errno 17] Datei existiert: '/ var/log/dummy'

Traceback (letzter Anruf zuletzt): Datei "corrupt_test.py", Zeile 245, in main create_logdir () Datei "corrupt_test.py", Zeile 53, in create_logdir os.makedirs (LOG_DIR) Datei "/usr/local/lib/python2.7/os.py", Zeile 157, in makedirs OSError: [Errno 17] Datei existiert: '/ var/log/dummy'

Ich bevorzuge den Bubble-Out-Ansatz, perhap mit einem Log oder einer Warnung. Nachrichten wie Sie getan haben, zB:

logging.exception ("create_logdir fehlgeschlagen: makedirs (% r):% s"% (LOG_DIR, e)) erhöhen

(Auch nicht, dass die Protokollnachricht mehr Kontext aufzeichnet: Kontext ist sehr hilfreich Nützlich beim Debuggen von Problemen.)

Für sehr kleine Skripte ist sys.stderr.write in Ordnung, aber im Allgemeinen eines von Ihre Funktionen, die sich im Allgemeinen als nützlich erwiesen haben, können migrieren in eine Bibliothek, um wiederverwendet zu werden; Bedenken Sie, dass stderr nicht .__ ist. immer der Ort für Nachrichten; Lesen Sie stattdessen für das Protokollierungsmodul mit error () oder wanr () oder exception (). Es gibt mehr Konfigurationsbereich, in dem der Ausgang ohne Verkabelung so verläuft es in deine inneren Funktionen.

  1. Kann ich nur erhöhen, anstatt SystemExit oder sys.exit (1). Diese sieht für mich falsch aus

    def main ():

    versuchen: create_logdir () Ausnahme Ausnahme als e logging.exception (e) erziehen

Das würde ich selbst tun.

Denken Sie: Wurde die Ausnahme "behandelt", bedeutet dies die Situation behandelt worden, weil es erwartet wurde? Wenn nicht, lassen Sie die Ausnahme Blase aus, damit der Benutzer weiß, dass etwas nicht von .__ verstanden wird. Das Programm ist aufgetreten.

Schließlich ist es generell schlecht für SystemExit oder sys.exit () von innen etwas anderes als die äußerste main () - Funktion. Und ich widersetze mich sogar dort; Die Hauptfunktion kann, wenn sie gut geschrieben ist, oft als .__ bezeichnet werden. von irgendwo anders nützlich, und das macht es effektiv zu einer Bibliothek Funktion (es wurde wiederverwendet). Eine solche Funktion sollte nicht das Programm einseitig abbrechen. Wie unhöflich! Lassen Sie stattdessen die Ausnahme Blase raus: Vielleicht erwartet der caller von main () es und kann damit umgehen es. Indem Sie abbrechen und nicht "erhöhen", haben Sie den Anrufer von .__ beraubt. die Chance, etwas angemessenes zu tun, auch wenn Sie selbst (d. h. "main") kennen nicht genügend Kontext, um die Ausnahme zu behandeln.

Also bin ich für "Raise". Und dann nur, weil Sie die .__ protokollieren möchten. Error. Wenn Sie die Ausnahme nicht protokollieren möchten, können Sie das .__ vermeiden. versuchen Sie/mit Ausnahme von vollständig und haben einfacheren Code: Lassen Sie den Anrufer sich sorgen. über unbehandelte Ausnahmen!

0
serv-inc