2010-01-22 13 views
9

Opzione 1:quale stile è preferito?

def f1(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    if c in d: 
    return d[c] 

    return "N/A" 

Opzione 2:

def f2(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    try: 
    return d[c] 
    except: 
    return "N/A" 

In modo che posso quindi chiamare:

for c in ("China", "Japan"): 
    for f in (f1, f2): 
    print "%s => %s" % (c, f(c)) 

Le opzioni sono per determinare sia se la chiave è nella directory prima mano (f1), o semplicemente fallback all'eccezione (f2). Quale è il preferito? Perché?

+8

eccetto: è cattivo karma. Sii sempre specifico su ciò che ti interessa catturare, in questo caso KeyError – richo

+2

Hai scelto un esempio scarso. La risposta ovvia non coinvolge nessuno stile. – Omnifarious

risposta

9

In genere, le eccezioni comportano un sovraccarico e sono pensate per casi veramente "eccezionali". In questo caso, sembra una parte normale dell'esecuzione, non uno stato 'eccezionale' o 'errore'.

In generale, penso che il tuo codice trarrà vantaggio dall'utilizzo della convenzione "if/else" e dal salvataggio delle eccezioni solo quando sono veramente necessarie.

+2

che mi ricorda "codice come pensi", "le cose funzionano meglio come hanno progettato". quindi lo segnalo come risposta. –

+0

Si potrebbe essere corretti quando si dice che le eccezioni arrivano con un sovraccarico, ma lo stile python è "È meglio chiedere perdono che il permesso". Ciò significa che non controlli se qualcosa è lì o no. Provaci e fallo e più tardi chiedi perdono. Se fossi in me, sarei andato con un 'try/except' –

+2

Questo è un buon punto jeffjose. È intelligente in Python provare le cose e vedere cosa funziona. Comunque usando una clausola try/except in questo caso, quando non ci aspettiamo nulla di eccezionale, non è una buona idea. Come Richo ha detto: "cattivo karma".:-) –

21

Né, vorrei andare per

def f2(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    return d.get(c, "N/A") 

In questo modo è più breve e "get" è stato progettato per il lavoro.

Anche un'eccezione senza un'eccezione esplicita è una cattiva pratica, quindi utilizzare except KeyError: non solo eccetto.

Le eccezioni non hanno un sovraccarico in Python. In genere è meglio usarli se non ci sono alternative migliori o qualche volta anche quando salva una ricerca attributo (da usare al posto di hasattr).

Modifica: per chiarire il punto generale sulle eccezioni.

paxdiablo è corretto sul punto generale. Python è progettato principalmente per "è più facile chiedere perdono e quindi il permesso", quindi provare a vedere cosa fallisce (eccezioni), quindi "guarda prima di saltare" vedere che cosa è lì e poi applicare. Questo perché la ricerca degli attributi in python può essere costosa, quindi richiamare di nuovo le stesse cose (per controllare i confini) è uno spreco di risorse. Tuttavia, roba interna in Python ha normalmente ottenuto aiutanti più belli, quindi è meglio usarli.

+0

la domanda non è specifica per dict, è principalmente per la mostra. quello che voglio sapere è controllare i confini prima o ritirarsi in eccezione. –

+1

@Dyno: allora avresti dovuto chiedere * che *. Una buona regola empirica è "meglio chiedere il perdono che il permesso", ma aggiungerò che se il caso comune sta andando a chiedere molto perdono, allora dovresti chiedere prima il perdono. –

+0

intendi "fallo e basta". se va male, poi affrontarlo in seguito? –

7

Nessuno dei due.

return d.get(c, 'N/A') 
11

In termini generali (non necessariamente Python), tendo a preferire il metodo di "prova-poi-tell-me-se-da-andato-sbagliato" (eccezioni) in tutti, ma i casi più semplici. Questo perché, negli ambienti con thread o durante l'accesso al database, i dati sottostanti possono cambiare tra il controllo della chiave e l'estrazione del valore.

Se non si modifica l'array associativo al di fuori del thread corrente, è possibile eseguire il metodo "check-first-then-extract".

Ma questo è per il caso generale. Qui, in particolare, è possibile utilizzare il metodo get che consente di specificare un valore predefinito se la chiave non esiste:

return d.get (c, "N/A") 

te lo chiarire ciò che ho detto nel primo paragrafo.In situazioni in cui i dati sottostanti possono cambiare tra il controllo e l'utilizzo, è necessario sempre utilizzare un'operazione di tipo eccezione (a meno che non si disponga di un'operazione che non causerà un problema, ad esempio d.get(), menzionato sopra). Si consideri ad esempio, i seguenti due filo linee temporali:

+------------------------------+--------------------+ 
| Thread1      | Thread2   | 
+------------------------------+--------------------+ 
| Check is NY exists as a key. |     | 
|        | Delete NY key/val. | 
| Extract value for NY.  |     | 
+------------------------------+--------------------+ 

Quando il filo 1 tenta di estrarre il valore, si otterrà un'eccezione comunque, quindi si può anche solo codice per la possibilità e rimuovere il controllo iniziale.

Il commento sui database è anche rilevante poiché questa è un'altra situazione in cui i dati sottostanti possono cambiare. Ecco perché tendo a preferire l'SQL atomico (ove possibile) piuttosto che qualcosa come ottenere una lista di chiavi e poi elaborarle con dichiarazioni individuali.

+0

Li ho sempre chiamati. È più facile chiedere perdono quindi il permesso "e" guardare prima di saltare "rispettivamente.Ma sono d'accordo nel perdono di Python è quello che stai cercando –

+0

tendo a segnare sia questo che jweede come risposta, ma sembra che questo non sia fattibile. –

4

Sono con David su questo:

def f2(c): 
    d = { 
     "USA": "N.Y.", 
     "China": "Shanghai" 
     } 

    return d.get(c, "N/A") 

... è esattamente come avrei scritto io.

Per affrontare le altre opzioni:

In 'f1()', non c'è niente di sbagliato in questo, di per sé, ma dizionari hanno un metodo get() per praticamente questo caso esatto uso: "ottenere questo da il ditt, e se non è lì, restituisci invece quest'altra cosa ". Questo è tutto quello che dice il tuo codice, usando get() è solo più conciso.

In 'f2()', usare 'except' da solo come se fosse disapprovato, e inoltre, non si fa nulla di utile in risposta all'eccezione - nel tuo caso il codice chiamante non sarà mai sapere che c'era un'eccezione. Allora perché usare il costrutto se non aggiunge valore alla tua funzione o al codice che lo chiama?

1

Vedo persone che usano "get", che consiglio. Tuttavia, se vi trovate in una situazione simile in futuro, intercettare l'eccezione cercavi:

try: 
    return d[k] 
except KeyError: 
    return "N/A" 

In questo modo, altre eccezioni (tra cui KeyboardInterrupt) non farsi prendere. Non vuoi quasi mai catturare lo KeyboardInterrupt.

0

Sono d'accordo che in questo caso, dict.get è la soluzione migliore.

In generale, penso che la vostra scelta dipenderà da quanto probabile siano le eccezioni. Se ti aspetti che la maggior parte delle ricerche di chiavi passino, allora il try/catch è una scelta migliore IMO. Allo stesso modo, se falliscono spesso, una dichiarazione if è migliore.

Le prestazioni delle eccezioni rispetto alle ricerche di attributi non sono così diverse in Python, quindi mi preoccuperei di più della logica dell'utilizzo di eccezioni/look-you-you-jump rispetto agli aspetti relativi alle prestazioni.

Problemi correlati