2013-02-17 12 views
26

Ho un oggetto "myobject", che potrebbe restituire None. Se restituisce None, non restituirà un attributo "id":Come posso restituire un valore predefinito per un attributo?

a = myobject.id 

Così, quando myobject è None, lo stament sopra i risultati in un AttributeError:

AttributeError: 'NoneType' object has no attribute 'id' 

Se myobject vale None, allora Voglio "a" uguale a Nessuno. Come si evita questa eccezione in una dichiarazione la linea, come ad esempio:

a= default(myobject.id, None) 

risposta

71

è necessario utilizzare l'involucro getattr invece di recuperare direttamente il valore di id.

a = getattr(myobject, 'id', None) 

Questo è come dire "Vorrei recuperare l'attributo id dall'oggetto myobject, ma se non v'è alcun attributo id all'interno dell'oggetto myobject, per poi tornare None, invece." Ma lo fa in modo efficiente.

Alcuni oggetti supportano anche la seguente forma di getattr accesso:

a = myobject.getattr('id', None) 

Secondo la richiesta OP, 'deep getattr':

def deepgetattr(obj, attr): 
    """Recurses through an attribute chain to get the ultimate value.""" 
    return reduce(getattr, attr.split('.'), obj) 
# usage: 
print deepgetattr(universe, 'galaxy.solarsystem.planet.name') 

semplice spiegazione:

Reduce è come un sul posto funzione ricorsiva.Ciò che fa in questo caso è iniziare con il obj (universo) e poi ricorsivamente ottenere più profondo per ogni attributo si tenta di accedere utilizzando getattr, così nella tua domanda sarebbe come questo:

a = getattr(getattr(myobject, 'id', None), 'number', None)

+1

+1, Questa è probabilmente l'idea migliore, non so perché non ci ho pensato. –

+0

Ha, grazie, userà il tuo sostegno per una spudorata promozione di sé: P –

+0

@Inbar Rose E se voglio farlo nell'attributo dell'attributo nello stesso modo, come 'a = mioobject.id.number'? – alwbtc

10

Il modo più semplice è quello di utilizzare l'operatore ternario:

a = myobject.id if myobject is not None else None 

L'operatore ternario restituisce la prima espressione se il valore medio è vero, altrimenti restituisce la seconda espressione.

Nota che si potrebbe anche fare questo in un altro modo, con eccezioni:

try: 
    a = myobject.id 
except AttributeError: 
    a = None 

Questo si inserisce la Pythonic ideale che è più facile chiedere perdono che il permesso - cosa è meglio dipenderà dalla situazione.

+0

vuol valutare veloce? Ho 30000 oggetti per fare questo controllo. – alwbtc

+0

@alwbtc Provalo e guarda. Controlla il modulo 'timeit'. Se pensi che sia molto probabile che una grande proporzione di valori sia 'None', il primo metodo sarà probabilmente più veloce, altrimenti usa il secondo. –

+0

OK, nessuno valore non è molto. Quindi userò il secondo metodo. Ma voglio anche il codice composto da one-liner. Non credi che le dichiarazioni di una sola riga siano migliori? – alwbtc

0
try: 
    a = myobject.id 
except AttributeError: 
    a = None 

lavorerà anche ed è più chiaro, IMO

+0

Non sono uno specialista in pitone, ma nella maggior parte dei linguaggi con cui ho avuto a che fare, cadere nell'istruzione "except" ha un costo aggiuntivo non sostanziale. In un caso semplice come questo, consiglierei "getattr" "approch (supponendo che questo sia meno costoso) Qualcuno di voi può dire qualcosa in più sul metodo getattr? –

+0

ottimizzazione prematura, bravo ragazzo, ottimizzazione prematura – hd1

+2

Questo non è l'ottimizzazione prematura.Utilizzo di eccezioni per gestire il comportamento normale è generalmente considerato in cattivo stile – francoisr

0
a=myobect.id if myobject else None 
1

Help on built-in function getattr in module builtins:

getattr(...) 
    getattr(object, name[, default]) -> value 

Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case.

seguente dovrebbe funzionare:

a = getattr(myobject, 'id', None) 
6

nella mia classe di oggetti si può mettere ignorare

class Foo(object): 
    def __getattribute__(self, name): 
     if not name in self; 
     return None; 
     else: 
     # Default behaviour 
     return object.__getattribute__(self, name) 
0

Se si vuole risolvere il problema nella definizione della classe di myobject (come in Black Diamond's answer) si può semplicemente definire __getattr__ per tornare None:

class Myobject: 
    def __getattr__(self, name): 
     return None 

Questo funziona perché __getattr__ viene chiamato solo quando tentando di accedere ad un attributo che non esiste, mentre __getattribute__ viene sempre chiamato prima indipendentemente dal nome dell'attributo. (Vedi anche this SO post.)

Per provare:

myobject = Myobject() 
print myobject.id 
myobject.id = 7 
print myobject.id 
Problemi correlati