Was ist die beabsichtigte Verwendung der optionalen else
Klausel der try
Erklärung?
Was ist die beabsichtigte Verwendung der optionalen else
Klausel der try
Erklärung?
Antworten:
Die Anweisungen im else
Block werden ausgeführt, wenn die Ausführung am Ende von try
- abfällt, wenn keine Ausnahme vorliegt. Ehrlich gesagt habe ich nie einen Bedarf gefunden.
Allerdings Behandeln von Ausnahmen Hinweise:
Die Verwendung der else-Klausel ist besser als das Hinzufügen von zusätzlichem Code zur try-Klausel, da dadurch vermieden wird, dass versehentlich eine Ausnahme abgefangen wird, die nicht durch den durch die try ... außer -Anweisung geschützten Code ausgelöst wurde.
Wenn Sie also eine Methode haben, die beispielsweise eine auslösen könnte, IOError
und Sie Ausnahmen abfangen möchten, die ausgelöst werden, möchten Sie noch etwas tun, wenn die erste Operation erfolgreich ist und Sie keinen IOError abfangen möchten Bei dieser Operation könnten Sie so etwas schreiben:
try:
operation_that_can_throw_ioerror()
except IOError:
handle_the_exception_somehow()
else:
# we don't want to catch the IOError if it's raised
another_operation_that_can_throw_ioerror()
finally:
something_we_always_need_to_do()
Wenn Sie nur another_operation_that_can_throw_ioerror()
nach setzen operation_that_can_throw_ioerror
, except
würde der Fehler des zweiten Anrufs abfangen. Und wenn Sie es nach dem ganzen try
Block setzen, wird es immer ausgeführt und erst nach dem finally
. Mit else
können Sie sicher gehen
finally
Block ausgeführt, undIOError
s, die es erhöht, werden hier nicht gefangenreturn
, continue
oder break
.
Es gibt einen großen Grund für die Verwendung else
- Stil und Lesbarkeit. Im Allgemeinen ist es eine gute Idee, Code beizubehalten, der Ausnahmen in der Nähe des Codes verursachen kann, der sich mit ihnen befasst. Vergleichen Sie zum Beispiel diese:
try:
from EasyDialogs import AskPassword
# 20 other lines
getpass = AskPassword
except ImportError:
getpass = default_getpass
und
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
else:
# 20 other lines
getpass = AskPassword
Der zweite ist gut, wenn der except
nicht vorzeitig zurückkehren oder die Ausnahme erneut auslösen kann. Wenn möglich hätte ich geschrieben:
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
return False # or throw Exception('something more descriptive')
# 20 other lines
getpass = AskPassword
Hinweis: Die Antwort wurde von einem kürzlich veröffentlichten Duplikat hier kopiert , daher all das "AskPassword" -Ding.
Eine Verwendung: Testen Sie einen Code, der eine Ausnahme auslösen soll.
try:
this_should_raise_TypeError()
except TypeError:
pass
except:
assert False, "Raised the wrong exception type"
else:
assert False, "Didn't raise any exception"
(Dieser Code sollte in der Praxis in einen allgemeineren Test abstrahiert werden.)
Python try-else
Was ist die beabsichtigte Verwendung der optionalen
else
Klausel der try-Anweisung?
Die beabsichtigte Verwendung besteht darin, einen Kontext zu haben, in dem mehr Code ausgeführt werden kann, wenn es keine Ausnahmen gab, in denen erwartet wurde, dass er verarbeitet wird.
Dieser Kontext vermeidet die versehentliche Behandlung von Fehlern, die Sie nicht erwartet haben.
Aber es ist wichtig , die genauen Bedingungen zu verstehen, die sonst Klausel Sicht verursachen, weil return
, continue
und break
kann den Steuerfluss zu unterbrechen else
.
Die else
Anweisung läuft , wenn es keine Ausnahmen und wenn nicht durch eine unterbrochen return
, continue
oder break
Aussage.
Die optionale
else
Klausel wird ausgeführt, wenn die Kontrolle am Ende dertry
Klausel abläuft. *
(Fettdruck hinzugefügt.) Und die Fußnote lautet:
* Derzeit Kontrolle „abfließt Ende“ außer im Fall einer Ausnahme oder die Ausführung einer
return
,continue
oderbreak
Aussage.
Es ist mindestens eine vorhergehende Ausnahmeklausel erforderlich ( siehe Grammatik ). Es ist also wirklich nicht "try-else", sondern "try-without-else (-finally)", wobei else
(und finally
) optional sind.
Das Python-Tutorial erläutert die beabsichtigte Verwendung:
Die Anweisung try ... without enthält eine optionale else-Klausel, die, sofern vorhanden, allen Ausnahmeregelungen folgen muss. Dies ist nützlich für Code, der ausgeführt werden muss, wenn die try-Klausel keine Ausnahme auslöst. Zum Beispiel:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
Die Verwendung der else-Klausel ist besser als das Hinzufügen von zusätzlichem Code zur try-Klausel, da dadurch vermieden wird, dass versehentlich eine Ausnahme abgefangen wird, die nicht durch den durch die try ... außer -Anweisung geschützten Code ausgelöst wurde.
else
Code und Code nach dem try
BlockWenn Sie einen Fehler behandeln, wird der else
Block nicht ausgeführt. Zum Beispiel:
def handle_error():
try:
raise RuntimeError('oops!')
except RuntimeError as error:
print('handled a RuntimeError, no big deal.')
else:
print('if this prints, we had no error!') # won't print!
print('And now we have left the try block!') # will print!
Und nun,
>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!
Try-außer-else eignet sich hervorragend zum Kombinieren des EAFP-Musters mit Enten-Typisierung :
try:
cs = x.cleanupSet
except AttributeError:
pass
else:
for v in cs:
v.cleanup()
Sie könnten sagen, dass dieser naive Code in Ordnung ist:
try:
for v in x.cleanupSet:
v.clenaup()
except AttributeError:
pass
Dies ist eine großartige Möglichkeit, um schwerwiegende Fehler in Ihrem Code versehentlich zu verbergen. Ich habe dort eine Bereinigung getippt, aber der AttributeError, der mich wissen lassen würde, wird verschluckt. Schlimmer noch, was wäre, wenn ich es richtig geschrieben hätte, aber die Bereinigungsmethode wurde gelegentlich an einen Benutzertyp übergeben, der ein falsch benanntes Attribut hatte, was dazu führte, dass es auf halbem Weg stillschweigend fehlschlug und eine Datei nicht geschlossen blieb? Viel Glück beim Debuggen.
Ich finde es wirklich nützlich, wenn Sie Aufräumarbeiten durchführen müssen, auch wenn es eine Ausnahme gibt:
try:
data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
handle_exception(e)
else:
do_stuff(data)
finally:
clean_up()
Auch wenn Sie sich momentan keine Verwendung vorstellen können, können Sie darauf wetten, dass es eine Verwendung dafür geben muss. Hier ist ein einfallsloses Beispiel:
Mit else
:
a = [1,2,3]
try:
something = a[2]
except:
print "out of bounds"
else:
print something
Ohne else
:
try:
something = a[2]
except:
print "out of bounds"
if "something" in locals():
print something
Hier haben Sie die Variable something
definiert, wenn kein Fehler ausgegeben wird. Sie können dies außerhalb des try
Blocks entfernen , aber dann ist eine unordentliche Erkennung erforderlich, wenn eine Variable definiert ist.
something = a[2]; print something
dem try: block?
Es gibt ein schönes Beispiel try-else
in PEP 380 . Grundsätzlich kommt es darauf an, in verschiedenen Teilen des Algorithmus unterschiedliche Ausnahmebehandlungen durchzuführen.
Es ist ungefähr so:
try:
do_init_stuff()
except:
handle_init_suff_execption()
else:
try:
do_middle_stuff()
except:
handle_middle_stuff_exception()
Auf diese Weise können Sie den Code für die Ausnahmebehandlung näher an die Stelle schreiben, an der die Ausnahme auftritt.
Aus Fehlern und Ausnahmen # Behandlung von Ausnahmen - docs.python.org
Die
try ... except
Anweisung enthält eine optionaleelse
Klausel, die, sofern vorhanden, allen außer Klauseln folgen muss. Dies ist nützlich für Code, der ausgeführt werden muss, wenn die try-Klausel keine Ausnahme auslöst. Zum Beispiel:for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
Die Verwendung der else-Klausel ist besser als das Hinzufügen von zusätzlichem Code zur try-Klausel, da dadurch vermieden wird, dass versehentlich eine Ausnahme abgefangen wird, die nicht durch den durch die try ... außer -Anweisung geschützten Code ausgelöst wurde.
Wenn man sich die Python-Referenz ansieht, scheint sie else
ausgeführt zu werden, try
wenn es keine Ausnahme gibt. Die optionale else-Klausel wird ausgeführt, wenn die Steuerung am Ende der try-Klausel abläuft. 2 Ausnahmen in der else-Klausel werden von den vorhergehenden Ausnahmen nicht behandelt.
Das Eintauchen in Python hat ein Beispiel, in dem, wenn ich das richtig verstehe, im try
Block versucht wird, ein Modul zu importieren. Wenn dies fehlschlägt, erhalten Sie eine Ausnahme und binden die Standardeinstellung. Wenn dies funktioniert, haben Sie die Möglichkeit, in den else
Block zu gehen und die erforderlichen Elemente zu binden (siehe Link für das Beispiel und die Erklärung).
Wenn Sie versucht haben, im catch
Block zu arbeiten, könnte dies eine weitere Ausnahme auslösen - ich denke, hier ist der else
Block nützlich.
try
Block zurückkehren können.
Das ist es. Der 'else'-Block einer try-exception-Klausel existiert für Code, der ausgeführt wird, wenn (und nur wenn) die versuchte Operation erfolgreich ist. Es kann verwendet und missbraucht werden.
try:
fp= open("configuration_file", "rb")
except EnvironmentError:
confdata= '' # it's ok if the file can't be opened
else:
confdata= fp.read()
fp.close()
# your code continues here
# working with (possibly empty) confdata
Persönlich mag ich es und benutze es, wenn es angebracht ist. Es gruppiert Anweisungen semantisch.
Vielleicht könnte eine Verwendung sein:
#debug = []
def debuglog(text, obj=None):
" Simple little logger. "
try:
debug # does global exist?
except NameError:
pass # if not, don't even bother displaying
except:
print('Unknown cause. Debug debuglog().')
else:
# debug does exist.
# Now test if you want to log this debug message
# from caller "obj"
try:
if obj in debug:
print(text) # stdout
except TypeError:
print('The global "debug" flag should be an iterable.')
except:
print('Unknown cause. Debug debuglog().')
def myfunc():
debuglog('Made it to myfunc()', myfunc)
debug = [myfunc,]
myfunc()
Vielleicht führt dich das auch zu einer Verwendung.
Ich habe festgestellt, dass das try: ... else:
Konstrukt in der Situation nützlich ist, in der Sie Datenbankabfragen ausführen und die Ergebnisse dieser Abfragen in einer separaten Datenbank mit demselben Geschmack / Typ protokollieren. Angenommen, ich habe viele Arbeitsthreads, die alle Datenbankabfragen verarbeiten, die an eine Warteschlange gesendet werden
#in a long running loop
try:
query = queue.get()
conn = connect_to_db(<main db>)
curs = conn.cursor()
try:
curs.execute("<some query on user input that may fail even if sanitized">)
except DBError:
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of failed query")
logcurs.close()
logconn.close()
else:
#we can't put this in main try block because an error connecting
#to the logging DB would be indistinguishable from an error in
#the mainquery
#We can't put this after the whole try: except: finally: block
#because then we don't know if the query was successful or not
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of successful query")
logcurs.close()
logconn.close()
#do something in response to successful query
except DBError:
#This DBError is because of a problem with the logging database, but
#we can't let that crash the whole thread over what might be a
#temporary network glitch
finally:
curs.close()
conn.close()
#other cleanup if necessary like telling the queue the task is finished
Wenn Sie zwischen den möglichen Ausnahmen unterscheiden können, die möglicherweise ausgelöst werden, müssen Sie dies natürlich nicht verwenden. Wenn Code jedoch auf einen erfolgreichen Code reagiert, wird möglicherweise dieselbe Ausnahme wie beim erfolgreichen Teil ausgelöst, und Sie können dies nicht einfach tun Lassen Sie die zweite mögliche Ausnahme los oder kehren Sie sofort nach Erfolg zurück (was in meinem Fall den Thread töten würde), dann ist dies praktisch.
Ein else
Block kann häufig vorhanden sein, um die Funktionalität zu ergänzen, die in jedem except
Block auftritt .
try:
test_consistency(valuable_data)
except Except1:
inconsistency_type = 1
except Except2:
inconsistency_type = 2
except:
# Something else is wrong
raise
else:
inconsistency_type = 0
"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""
In diesem Fall inconsistency_type
wird in jedem Ausnahmeblock gesetzt, so dass das Verhalten im fehlerfreien Fall in ergänzt wird else
.
Natürlich beschreibe ich dies als ein Muster, das eines Tages in Ihrem eigenen Code auftauchen kann. In diesem speziellen Fall setzen Sie ohnehin nur inconsistency_type
vor dem try
Block auf 0 .
Hier ist ein weiterer Ort, an dem ich dieses Muster verwenden möchte:
while data in items:
try
data = json.loads(data)
except ValueError as e:
log error
else:
# work on the `data`
continue
stattdessen einfach das Muster "Früh ausbrechen" verwenden. Auf diese Weise können Sie die "else" -Klausel und ihren Einzug löschen, um den Code leichter lesbar zu machen.
Eines der Anwendungsszenarien, an die ich denken kann, sind unvorhersehbare Ausnahmen, die umgangen werden können, wenn Sie es erneut versuchen. Wenn die Operationen im try-Block beispielsweise Zufallszahlen enthalten:
while True:
try:
r = random.random()
some_operation_that_fails_for_specific_r(r)
except Exception:
continue
else:
break
Wenn die Ausnahme jedoch vorhergesagt werden kann, sollten Sie die Validierung immer vor einer Ausnahme auswählen. Es kann jedoch nicht alles vorhergesagt werden, so dass dieses Codemuster seinen Platz hat.
break
Innere try
am Ende platzieren, was IMO sauberer ist, und Sie brauchen das nicht else
. Auch das continue
wird nicht wirklich benötigt, kann man einfach pass
.
Ich habe festgestellt, dass es else
nützlich ist, mit einer möglicherweise falschen Konfigurationsdatei umzugehen:
try:
value, unit = cfg['lock'].split()
except ValueError:
msg = 'lock monitoring config must consist of two words separated by white space'
self.log('warn', msg)
else:
# get on with lock monitoring if config is ok
Eine Ausnahme beim Lesen der lock
Konfiguration deaktiviert die Sperrüberwachung, und ValueErrors protokolliert eine hilfreiche Warnmeldung.
Angenommen, Ihre Programmierlogik hängt davon ab, ob ein Wörterbuch einen Eintrag mit einem bestimmten Schlüssel hat. Sie können das Ergebnis der dict.get(key)
Verwendung von if... else...
Konstrukt testen oder Folgendes tun:
try:
val = dic[key]
except KeyError:
do_some_stuff()
else:
do_some_stuff_with_val(val)
Ich würde einen weiteren Anwendungsfall hinzufügen, der bei der Behandlung von DB-Sitzungen unkompliziert erscheint:
# getting a DB connection
conn = db.engine.connect()
# and binding to a DB session
session = db.get_session(bind=conn)
try:
# we build the query to DB
q = session.query(MyTable).filter(MyTable.col1 == 'query_val')
# i.e retrieve one row
data_set = q.one_or_none()
# return results
return [{'col1': data_set.col1, 'col2': data_set.col2, ...}]
except:
# here we make sure to rollback the transaction,
# handy when we update stuff into DB
session.rollback()
raise
else:
# when no errors then we can commit DB changes
session.commit()
finally:
# and finally we can close the session
session.close()
Der else:
Block ist verwirrend und (fast) nutzlos. Es ist auch Teil der for
und while
Aussagen.
Selbst auf einer if
Aussage else:
kann das auf wirklich schreckliche Weise missbraucht werden, was zu Fehlern führt, die sehr schwer zu finden sind.
Bedenken Sie.
if a < 10:
# condition stated explicitly
elif a > 10 and b < 10:
# condition confusing but at least explicit
else:
# Exactly what is true here?
# Can be hard to reason out what condition is true
Überlegen Sie zweimal else:
. Es ist im Allgemeinen ein Problem. Vermeiden Sie es, außer in einer if
Anweisung, und dokumentieren Sie auch dann die else
Bedingung, um es explizit zu machen.
if x > 0: return "yes"
und if x <= 0: return "no"
. Jetzt kommt eine Person und ändert eine der Bedingungen, um zu sagen x > 1
, vergisst aber, die andere zu ändern. Wie reduziert sich die Anzahl der Fehler, die begangen werden würden? if else
Klauseln sind manchmal viele Zeilen voneinander entfernt. DRY ist eine gute Praxis, viel öfter als nicht. (Entschuldigung für den doppelten Beitrag).