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:

  1. De except zonder uitzonderingstype (regel 5) zal zelfs gezonde uitzonderingen opvangen, inclusief KeyboardInterrupt . Dat voorkomt dat het programma in sommige gevallen wordt afgesloten.
  2. Het uitzonderingblok herstelt de fout niet, wat betekent dat we niet kunnen zien of de uitzondering binnen get_result of omdat res een lege lijst was.
  3. 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, blijft res volledig uitgeschakeld en zal de verwijzing naar res in het uitzonderingsblok NameError , 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



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow