Perdono di Python contro l'autorizzazione e la digitazione di anatre

42

In Python, sento spesso che è meglio "chiedere perdono" (cattura delle eccezioni) invece di "chiedere il permesso" (controllo di tipo / condizione). Per quanto riguarda l'imposizione della digitazione anatra in Python, è questo

try:
    x = foo.bar
except AttributeError:
    pass
else:
    do(x)

migliore o peggiore di

if hasattr(foo, "bar"):
    do(foo.bar)
else:
    pass

in termini di prestazioni, leggibilità, "pythonic" o qualche altro fattore importante?

    
posta darkfeline 13.11.2012 - 08:37
fonte

4 risposte

58

Dipende molto da quanto spesso pensi che l'eccezione sarà lanciata.

Entrambi gli approcci sono, a mio parere, ugualmente validi, almeno in termini di leggibilità e pitonicità. Ma se il 90% dei tuoi oggetti non ha l'attributo bar noterai una differenza di prestazioni distinta tra i due approcci:

>>> import timeit
>>> def askforgiveness(foo=object()):
...     try:
...         x = foo.bar
...     except AttributeError:
...         pass
... 
>>> def askpermission(foo=object()):
...     if hasattr(foo, 'bar'):
...         x = foo.bar
... 
>>> timeit.timeit('testfunc()', 'from __main__ import askforgiveness as testfunc')
2.9459929466247559
>>> timeit.timeit('testfunc()', 'from __main__ import askpermission as testfunc')
1.0396890640258789

Ma se il 90% degli oggetti fanno hanno l'attributo, le tabelle sono state girate:

>>> class Foo(object):
...     bar = None
... 
>>> foo = Foo()
>>> timeit.timeit('testfunc(foo)', 'from __main__ import askforgiveness as testfunc, foo')
0.31336188316345215
>>> timeit.timeit('testfunc(foo)', 'from __main__ import askpermission as testfunc, foo')
0.4864199161529541

Quindi, dal punto di vista delle prestazioni, devi scegliere l'approccio più adatto alle tue circostanze.

Alla fine, un uso strategico del % modulo ditimeit potrebbe essere la cosa più pitonica puoi farlo.

    
risposta data 13.11.2012 - 10:24
fonte
9

In Python ottieni spesso prestazioni migliori facendo cose in modo Python. Con altri linguaggi, l'utilizzo di eccezioni per il controllo del flusso è generalmente considerato un'idea terribile perché le eccezioni in genere impongono un sovraccarico straordinario. Ma poiché questa tecnica è esplicitamente approvata in Python, l'interprete è ottimizzato per questo tipo di codice.

Come per tutte le domande sul rendimento, l'unico modo per essere certi è profilare il tuo codice. Scrivi entrambe le versioni e vedi quale corre più veloce. Sebbene nella mia esperienza, il "modo Python" è in genere il modo più veloce.

    
risposta data 13.11.2012 - 08:45
fonte
2

Le prestazioni, ritengo, sono una preoccupazione secondaria. Se ciò si verifica, un profiler ti aiuterà a concentrarti sui veri colli di bottiglia, che potrebbero o meno essere il modo in cui tratti eventuali argomenti illegali.

Leggere e semplicità, d'altra parte, sono sempre una preoccupazione primaria. Non ci sono regole rigide qui, basta usare il tuo giudizio.

Questa è una questione universale, ma le convenzioni specifiche per l'ambiente o la lingua sono rilevanti. Ad esempio, in Python di solito basta usare semplicemente l'attributo che ci si aspetta e lasciare che un possibile AttributeError raggiunga il chiamante.

    
risposta data 20.11.2012 - 09:07
fonte
-1

In termini di correttezza , penso che la gestione delle eccezioni sia la strada da percorrere (a volte uso l'approccio hasattr (), però). Il problema di base di affidarsi a hasattr () è che trasforma le violazioni dei contratti di codice in errori silenziosi (questo è un grosso problema in JavaScript, che non genera proprietà non esistenti).

    
risposta data 10.04.2015 - 16:56
fonte

Leggi altre domande sui tag