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
except
ohne 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_result
oder weilres
eine leere Liste war. - Am schlimmsten: Wenn wir uns Sorgen machten, dass das Ergebnis leer wäre, haben wir etwas Schlimmeres verursacht. Wenn
get_result
fehlschlägt, bleibtres
vollständig unset und der Verweis aufres
im außer -BlockNameError
, dassNameError
und 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