Python Language
Python-antipatronen
Zoeken…
Overzealous behalve clausule
Uitzonderingen zijn krachtig, maar een enkele overijverige behalve-clausule kan het allemaal in één regel wegnemen.
try: res = get_result() res = res[0] log('got result: %r' % res) except: if not res: res = '' print('got exception')
Dit voorbeeld toont 3 symptomen van het antipatroon:
- De
except
zonder uitzonderingstype (regel 5) zal zelfs gezonde uitzonderingen opvangen, inclusiefKeyboardInterrupt
. Dat voorkomt dat het programma in sommige gevallen wordt afgesloten. - Het uitzonderingblok herstelt de fout niet, wat betekent dat we niet kunnen zien of de uitzondering binnen
get_result
of omdatres
een lege lijst was. - Het ergste van alles, als we ons zorgen maken over het resultaat dat leeg is, hebben we iets veel ergers veroorzaakt. Als
get_result
mislukt, blijftres
volledig uitgeschakeld en zal de verwijzing naarres
in het uitzonderingsblokNameError
, waardoor de oorspronkelijke fout volledig wordt gemaskeerd.
Denk altijd aan het type uitzondering dat u probeert te hanteren. Lees de uitzonderingenpagina en krijg een idee van welke basisuitzonderingen er zijn.
Hier is een vaste versie van het bovenstaande voorbeeld:
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)
We vangen meer specifieke uitzonderingen op, waar nodig opnieuw. Nog een paar regels, maar oneindig veel correcter.
Kijk voordat je springt met processorintensieve functie
Een programma kan gemakkelijk tijd verspillen door meerdere keren een processorintensieve functie aan te roepen.
Neem bijvoorbeeld een functie die er als volgt uit: een integer geretourneerd als de input value
is, anders kan produceren None
:
def intensive_f(value): # int -> Optional[int]
# complex, and time-consuming code
if process_has_failed:
return None
return integer_output
En het kan op de volgende manier worden gebruikt:
x = 5
if intensive_f(x) is not None:
print(intensive_f(x) / 2)
else:
print(x, "could not be processed")
print(x)
Hoewel dit zal werken, heeft het het probleem van het aanroepen van intensive_f
, wat de duur van de code verdubbelt. Een betere oplossing is om vooraf de retourwaarde van de functie te krijgen.
x = 5
result = intensive_f(x)
if result is not None:
print(result / 2)
else:
print(x, "could not be processed")
Een duidelijkere en mogelijk meer pythonische manier is echter om uitzonderingen te gebruiken, bijvoorbeeld:
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 is geen tijdelijke variabele nodig. Het heeft vaak de voorkeur om een assert
statement te gebruiken en in plaats daarvan de AssertionError
te vangen.
Woordenboeksleutels
Een veel voorkomend voorbeeld van waar dit kan worden gevonden, is toegang tot woordenboeksleutels. Vergelijk bijvoorbeeld:
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)
met:
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)
Het eerste voorbeeld moet twee keer door het woordenboek kijken, en omdat dit een lang woordenboek is, kan het lang duren om dit elke keer te doen. De tweede vereist slechts één zoekopdracht door het woordenboek en bespaart dus veel processortijd.
Een alternatief hiervoor is het gebruik van dict.get(key, default)
, maar in veel omstandigheden kunnen complexere bewerkingen nodig zijn in het geval dat de sleutel niet aanwezig is