Interrogando il controllo del tipo pitone

5

Ho visto innumerevoli volte il seguente approccio suggerito per "prendere in una collezione di oggetti e fare X se X è una Y e ignorare l'oggetto altrimenti"

def quackAllDucks(ducks):
  for duck in ducks:
    try:
      duck.quack("QUACK")
    except AttributeError:
      #Not a duck, can't quack, don't worry about it
      pass

L'implementazione alternativa di seguito ottiene sempre critiche per il calo di prestazioni causato dal controllo dei tipi

def quackAllDucks(ducks):
  for duck in ducks:
    if hasattr(duck,"quack"):
      duck.quack("QUACK")

Tuttavia, mi sembra che nel 99% degli scenari si desideri utilizzare la seconda soluzione a causa di quanto segue:

  • Se l'utente ottiene i parametri errati, essi non verranno trattati come un'anatra e non ci sarà alcuna indicazione. Un sacco di tempo sarà sprecato a debugging perché non c'è ciarlatano in corso fino a quando l'utente non si rende finalmente conto del suo stupido errore. La seconda soluzione genererebbe una traccia dello stack non appena l'utente ha provato a ciarlare.
  • Se l'utente ha qualche bug nel loro metodo quack () che causa un AttributeError allora quei bug saranno inghiottiti silenziosamente. Ancora una volta il tempo sarà sprecato a scavare per il bug quando la seconda soluzione darebbe semplicemente una traccia dello stack che mostra il problema immediato.

In effetti, mi sembra che l'unica volta in cui vorresti utilizzare il primo metodo sia quando:

  • Il blocco di codice in questione si trova in una sezione estremamente critica delle prestazioni della tua applicazione. Seguendo il principio di "evitare l'ottimizzazione prematura", lo realizzeresti naturalmente, dopo aver implementato un approccio più sicuro e trovato un collo di bottiglia.
  • Ci sono molti tipi di oggetti di ciarlatura là fuori e sei interessato solo a ciarlare gli oggetti che sono ciarlatani con un insieme di argomenti molto specifico (questo mi sembra un caso molto raro).

Dato questo, perché così tante persone preferiscono il primo approccio rispetto al secondo approccio? Che cosa mi manca?

Inoltre, mi rendo conto che ci sono altre soluzioni (come l'uso di abcs) ma queste sono le due soluzioni che mi sembrano più frequenti per il caso base.

    
posta Pace 29.11.2012 - 15:23
fonte

2 risposte

6

Il motivo per cui dovresti usare la prima versione è le prestazioni. Sollevare un'eccezione è spesso più economico che chiamare un metodo o una funzione.

Il primo argomento che hai presentato per l'utilizzo della seconda versione non è abbastanza valido, poiché anche l'utilizzo di if hasattr(duck, 'quack'): impedirebbe in modo silenzioso la chiamata a duck.quack() e non verrebbe sollevata alcuna eccezione.

Il tuo secondo argomento si applica solo perché la tua implementazione non è corretta. Dovresti invece farlo in questo modo:

def quackAllDucks(ducks):
  for duck in ducks:
    try:
      duck.quack
    except AttributeError:
      #Not a duck, can't quack, don't worry about it
      continue
    duck.quack("QUACK")

Quindi qualsiasi eccezione sollevata all'interno di duck.quack() verrebbe propagata al chiamante di quackAllDucks() .

[EDIT]

delnan ha sollevato una buona domanda nel suo commento qui sotto. Mi ha portato a indagare ulteriormente e il modo consigliato ora sembra essere per utilizzare hasattr() .

Ma la soluzione migliore è probabilmente progettare il tuo programma in modo che non dipenda da tali test. Come ha detto Steve Oualline, " Se non scriviamo codice come questo, non dobbiamo preoccuparci di domande " .

    
risposta data 29.11.2012 - 18:24
fonte
0

Il problema è che non c'è differenza tra i due. duck.quack () chiama __ getattr__ per cercare l'attributo quack, quindi tenta di richiamare ciò che ritorna. hasattr fa la stessa chiamata di funzione __ getattr__ quindi restituisce false se lancia un'eccezione. Quindi, in sostanza, la seconda versione è identica alla prima versione, eccetto che hai una doppia panoramica dell'attributo quack.

    
risposta data 29.11.2012 - 20:09
fonte

Leggi altre domande sui tag