Python Language
Python-Anti-Patterns
Suche…
Übereifrig mit Ausnahme der Klausel
Ausnahmen sind mächtig, aber eine einzige übereifrige Ausnahme-Klausel kann alles in einer einzigen Zeile wegnehmen.
try:
res = get_result()
res = res[0]
log('got result: %r' % res)
except:
if not res:
res = ''
print('got exception')
Dieses Beispiel zeigt 3 Symptome des Antipattern:
- Die
exceptohne Ausnahmetyp (Zeile 5) fängt sogar fehlerhafte Ausnahmen auf, einschließlichKeyboardInterrupt. Dadurch wird das Programm in einigen Fällen möglicherweise nicht beendet. - Der Ausnahme-Block erhöht den Fehler nicht erneut, was bedeutet, dass wir nicht feststellen können, ob die Ausnahme innerhalb von
get_resultoder weilreseine leere Liste war. - Am schlimmsten: Wenn wir uns Sorgen machten, dass das Ergebnis leer wäre, haben wir etwas Schlimmeres verursacht. Wenn
get_resultfehlschlägt, bleibtresvollständig unset und der Verweis aufresim außer -BlockNameError, dassNameErrorund der ursprüngliche Fehler vollständig maskiert wird.
Denken Sie immer an die Art der Ausnahme, mit der Sie umgehen möchten. Lesen Sie die Ausnahmeseite und erfahren Sie, welche grundlegenden Ausnahmen bestehen.
Hier ist eine feste Version des obigen Beispiels:
import traceback
try:
res = get_result()
except Exception:
log_exception(traceback.format_exc())
raise
try:
res = res[0]
except IndexError:
res = ''
log('got result: %r' % res)
Wir stellen spezifischere Ausnahmen fest und reraisen wenn nötig. Ein paar Zeilen mehr, aber unendlich viel korrekter.
Schauen Sie, bevor Sie mit einer prozessorintensiven Funktion springen
Ein Programm kann leicht Zeit verschwenden, indem eine prozessorintensive Funktion mehrmals aufgerufen wird.
Nehmen wir zum Beispiel eine Funktion , die wie folgt aussieht: es eine ganze Zahl zurück , wenn der value ein, sonst produzieren kann None :
def intensive_f(value): # int -> Optional[int]
# complex, and time-consuming code
if process_has_failed:
return None
return integer_output
Und es könnte auf folgende Weise verwendet werden:
x = 5
if intensive_f(x) is not None:
print(intensive_f(x) / 2)
else:
print(x, "could not be processed")
print(x)
Während dies funktioniert, hat es das Problem, intensive_f aufzurufen, wodurch sich die Zeitdauer für die Ausführung des Codes verdoppelt. Eine bessere Lösung wäre, den Rückgabewert der Funktion vorher zu erhalten.
x = 5
result = intensive_f(x)
if result is not None:
print(result / 2)
else:
print(x, "could not be processed")
Ein klarer und möglicherweise pythonischerer Weg ist jedoch die Verwendung von Ausnahmen, zum Beispiel:
x = 5
try:
print(intensive_f(x) / 2)
except TypeError: # The exception raised if None + 1 is attempted
print(x, "could not be processed")
Hier wird keine temporäre Variable benötigt. Es kann oft vorzuziehen sein, eine assert Anweisung zu verwenden und stattdessen AssertionError abzufangen.
Wörterbuchschlüssel
Ein häufiges Beispiel dafür ist der Zugriff auf Wörterbuchschlüssel. Zum Beispiel vergleichen Sie:
bird_speeds = get_very_long_dictionary()
if "european swallow" in bird_speeds:
speed = bird_speeds["european swallow"]
else:
speed = input("What is the air-speed velocity of an unladen swallow?")
print(speed)
mit:
bird_speeds = get_very_long_dictionary()
try:
speed = bird_speeds["european swallow"]
except KeyError:
speed = input("What is the air-speed velocity of an unladen swallow?")
print(speed)
Im ersten Beispiel muss das Wörterbuch zweimal durchgesehen werden. Da es sich um ein langes Wörterbuch handelt, kann dies jedes Mal sehr lange dauern. Die zweite erfordert nur eine Suche durch das Wörterbuch und spart somit viel Prozessorzeit.
Eine Alternative dazu ist die Verwendung von dict.get(key, default) . In vielen Fällen können jedoch komplexere Vorgänge erforderlich sein, wenn der Schlüssel nicht vorhanden ist