2009-05-02 15 views
10

Qual è il modo divinatorio per designare codice irraggiungibile in Python come in:Come designare codice irraggiungibile python

gender = readFromDB(...) # either 'm' or 'f' 
if gender == 'm': 
    greeting = 'Mr.' 
elif gender == 'f': 
    greeting = 'Ms.' 
else: 
    # What should this line say? 
+5

Forse dovrebbe dire "Pat"? –

+0

Non penso che il codice irraggiungibile sia il termine corretto per questo. Vedi http://en.wikipedia.org/wiki/Unreachable_code – Unknown

+0

@unknown Che cosa suggeriresti invece? So che questo esempio non è buono, dato che il ciclo alternativo è di fatto raggiungibile. Ma come succede, è esattamente la "misura della raggiungibilità" che sto cercando. – phihag

risposta

24
raise ValueError('invalid gender %r' % gender) 
+1

Dal manifesto pitonico ... "... Gli errori non dovrebbero mai passare in silenzio. Salvo esplicitamente tacere". – jottos

7

Questo dipende da quanto sicuro siete del genere essere o 'm' o 'f'.

Se si è assolutamente certi, utilizzare if...else anziché if...elif...else. Semplicemente rende più facile per tutti.

Se ci sono possibilità di dati non corretti, tuttavia, dovresti probabilmente sollevare un'eccezione per rendere più facile il test e la risoluzione dei problemi. potresti utilizzare un saluto di genere neutro in questo caso, ma per qualcosa di più grande, i valori speciali rendono difficile trovare gli errori più difficili da trovare.

+0

/Quale/tipo di eccezione suggeriresti? E tutti sembrano essere coinvolti nell'esempio;). – phihag

+1

Probabilmente 'ValueError' come suggerito da altri. Sembra avere più senso: http://docs.python.org/library/exceptions.html – zenazn

+1

C'è * sempre * una possibilità di dati non validi. –

7

Si potrebbe sollevare un'eccezione:

raise ValueError("Unexpected gender; expected 'm' or 'f', got %s" % gender) 

o utilizzare un'asserzione falsa se si prevede che il database per restituire solo 'm' o 'f':

assert False, "Unexpected gender; expected 'm' or 'f', got %s" % gender 
+1

Penso che tu intenda 'asserire False' :) – Stephan202

+0

meh, riparato grazie :) – marcog

4

Io in realtà penso che ci sia un posto per questo.

class SeriousDesignError(Exception): 
    pass 

Così si può fare questo

if number % 2 == 0: 
    result = "Even" 
elif number % 2 == 1: 
    result = "Odd" 
else: 
    raise SeriousDesignError() 

Penso che questo sia il messaggio di errore più significativo. Questo genere di cose può consistere solo gli errori di progettazione (o cattiva manutenzione, che è la stessa cosa.)

+1

Includerei ancora una stringa descrittiva quando sollevo SDE, come 'raise SeriousDesignError ('I numeri devono essere pari o dispari')' – gomad

2

volte faccio:

if gender == 'm': 
    greeting = 'Mr.' 
else: 
    assert gender == 'f' 
    greeting = 'Ms.' 

penso che questo fa un buon lavoro di raccontare un lettore del codice che ci sono solo (in questo caso) due possibilità, e quali sono. Sebbene sia possibile sollevare un errore più descrittivo di AssertionError.

4

Dipende esattamente quello che vuoi l'errore da segnalare, ma vorrei usare un dizionario, in questo caso:

greetings={'m':'Mr.', 'f':'Ms.'} 
gender = readFromDB(...) # either 'm' or 'f' 
greeting=greetings[gender] 

Se genere non è né m né f, tale da far salire un KeyError contenente il valore inaspettato:

greetings={'m':'Mr.', 'f':'Ms.'} 

>>> greetings['W'] 

Traceback (most recent call last): 
    File "<pyshell#4>", line 1, in <module> 
    greetings['W'] 
KeyError: 'W' 

Se volete maggiori dettagli nel messaggio, si può prendere & controrilancio è:

try: 
    greeting = greetings[gender] 
except KeyError,e: 
    raise ValueError('Unrecognized gender %s'%gender) 
3

Fino ad ora, ho di solito usato una variazione sul risposta di John Fouhy - ma questo non è esattamente corretto, come sottolinea Ethan:

assert gender in ('m', 'f') 
if gender == 'm': 
    greeting = 'Mr.' 
else: 
    greeting = 'Ms.' 

Il problema principale con l'utilizzo di un'asserzione è che se qualcuno corre il vostro codice con i flag -O o -OO, i richiami vengono ottimizzati. Come Ethan indica di seguito, ciò significa che ora non hai alcun controllo dei dati. Le asserzioni sono un aiuto allo sviluppo e non dovrebbero essere utilizzate per la logica di produzione.Vado a prendere l'abitudine di usare un controllo funzionale() invece - questo permette per la sintassi chiamata pulito come un'asserzione:

def check(condition, msg=None): 
    if not condition: 
     raise ValueError(msg or '') 

check(gender in ('m', 'f')) 
if gender == 'm': 
    greeting = 'Mr.' 
else: 
    greeting = 'Ms.' 

Tornando alla domanda iniziale, mi sostengo che l'utilizzo di un assert() o controllare() prima del caso/logica il resto è più facile da leggere, più sicuro e più esplicito:

  • mette alla prova la qualità dei dati prima di iniziare ad agire su di esso - questo potrebbe essere importante se ci sono operatori diversi da '==' nella catena if/else
  • separa il test di asserzione dalla logica di branching, invece di interlacciarli - th rende la lettura e il refactoring più semplici
+0

Se vuoi per pre-verificare dovresti farlo con 'if gender not in ('m', 'f'): raise SomeException' poichè 'assert's può essere ottimizzato e quindi non hai alcuna verifica. –

+0

Arg. Giusto. Non uso mai -O o -OO quindi non mi preoccupo per il mio codice, ma sono d'accordo che è una cattiva abitudine. Risolverò la risposta. – stevegt

Problemi correlati