Sök…


Överflödigt utom klausul

Undantag är kraftfulla, men en enda övergripande utom klausul kan ta allt bort i en enda rad.

try:
    res = get_result()
    res = res[0]
    log('got result: %r' % res)
except:
    if not res:
        res = ''
    print('got exception')

Detta exempel visar tre symtom på antipattern:

  1. Den except utan undantag typ (linje 5) kommer att fånga även friska undantag, inklusive KeyboardInterrupt . Det kommer i vissa fall att förhindra att programmet går ut.
  2. Undantagsblocket upprepar inte felet, vilket innebär att vi inte kan se om undantaget kommer från get_result eller om res var en tom lista.
  3. Värst av allt, om vi var oroliga för att resultatet skulle vara tomt, har vi orsakat något mycket värre. Om get_result misslyckas, kommer res att förbli helt oförändrat, och hänvisningen till res i undantagsblocket kommer att höja NameError , vilket helt maskerar det ursprungliga felet.

Tänk alltid på vilken typ av undantag du försöker hantera. Ge undantagssidan en läs och få en känsla för vilka grundläggande undantag som finns.

Här är en fast version av exemplet ovan:

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)

Vi fångar mer specifika undantag och ökar om det behövs. Några fler rader, men oändligt mer korrekt.

Titta innan du hoppar med processorintensiv funktion

Ett program kan enkelt slösa bort tid genom att ringa en processorintensiv funktion flera gånger.

Ta till exempel en funktion som ser ut så här: det returnerar ett heltal om value kan producera ett, annars None :

def intensive_f(value): # int -> Optional[int]
   # complex, and time-consuming code
   if process_has_failed:
       return None
   return integer_output

Och det kan användas på följande sätt:

x = 5
if intensive_f(x) is not None:
    print(intensive_f(x) / 2)
else:
    print(x, "could not be processed")

print(x)

Även om detta kommer att fungera, har det problemet att ringa intensive_f , vilket fördubblar tiden för koden att köra. En bättre lösning skulle vara att få returneringsvärdet för funktionen i förväg.

x = 5
result = intensive_f(x)
if result is not None:
    print(result / 2)
else:
    print(x, "could not be processed")

Men ett tydligare och kanske mer pytoniskt sätt är att använda undantag, till exempel:

x = 5
try:
    print(intensive_f(x) / 2)
except TypeError: # The exception raised if None + 1 is attempted
    print(x, "could not be processed")

Här behövs ingen tillfällig variabel. Det kan ofta vara att föredra att använda en assert uttalande och fånga AssertionError istället.

Ordbok nycklar

Ett vanligt exempel på var detta kan hittas är att få åtkomst till ordboksnycklar. Jämför till exempel:

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)

med:

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)

Det första exemplet måste titta igenom ordboken två gånger, och eftersom det här är en lång ordbok kan det ta lång tid att göra det varje gång. Den andra kräver endast en sökning i ordboken och sparar därmed mycket processortid.

Ett alternativ till detta är att använda dict.get(key, default) , men många omständigheter kan kräva mer komplexa åtgärder för att göra om nyckeln inte finns



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow