Come sapere se un oggetto ha un attributo in Python


1635

C'è un modo in Python per determinare se un oggetto ha qualche attributo? Per esempio:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

Come puoi sapere se aha l'attributo propertyprima di usarlo?

Risposte:


2343

Prova hasattr():

if hasattr(a, 'property'):
    a.property

EDIT: Vedi la risposta di zweiterlinde di seguito, che offre buoni consigli su come chiedere perdono! Un approccio molto pitonico!

La pratica generale in Python è che, se è probabile che la proprietà sia presente per la maggior parte del tempo, è sufficiente chiamarla e lasciare che l'eccezione si propaga o intrappolarla con un blocco try / tranne. Questo sarà probabilmente più veloce di hasattr. Se è probabile che la proprietà non ci sia la maggior parte del tempo, o non sei sicuro, l'utilizzo hasattrsarà probabilmente più veloce rispetto alla caduta ripetuta in un blocco di eccezioni.


19
Sembra funzionare anche per verificare le funzioni nello spazio dei nomi, ad esempio: import string hasattr(string, "lower")
riviera

15
hasattrè esattamente lo stesso che usare try/ except AttributeError: il docstring di hasattr (in Python 2.7) dice che usa la mano getattr cattura le eccezioni.
Jeff Tratner,

8
@JeffTratner: hasattrpurtroppo non è esattamente la stessa di un try: ... except AttributeError:in Python 2.x poiché hasattrsarà catturare tutti un'eccezione . Si prega di vedere la mia risposta per un esempio e una soluzione semplice.
Martin Geisler,

632

Come Jarret Hardie ha risposto, hasattrfarà il trucco. Vorrei aggiungere, tuttavia, che molti nella comunità di Python raccomandano una strategia di "più facile chiedere perdono che permesso" (EAFP) piuttosto che "guardare prima di saltare" (LBYL). Vedi questi riferimenti:

EAFP vs LBYL (era Re: un po 'deluso finora)
EAFP vs LBYL @Code Like a Pythonista: Idiomatic Python

vale a dire:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

... è preferito a:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()

259
Ma come si fa a verificare che è stata la proprietà a.property a causare AttributeError e non qualcosa in doStuff ()? Sembra di no. Penso che sia davvero più facile chiedere perdono, ma molte volte è anche scorretto.
jpalecek,

286
EAFP sembra ... folle. HasAttr telegrafa ai futuri programmatori di manutenzione che stai verificando per un determinato attributo. Ottenere un'eccezione non dice nulla ai futuri programmatori e potrebbe condurre qualcuno nella tana del coniglio.
Ethan Heilman,

74
@ e5: hai un punto giusto in questo caso, ma in molti casi EAFP è l'unica opzione corretta. Ad esempio, se controlli l'esistenza di un file e poi lo apri, aspettandoti che esista definitivamente, il tuo codice è errato: il file può essere eliminato o rinominato tra il controllo e l'uso. Questo si chiama errore TOCTOU (Time-Of-Check-To-Time-Of-Use) e oltre a causare arresti anomali può anche essere una fonte di vulnerabilità della sicurezza.
Max

15
@EthanHeilman è folle solo quando c'è un'ambiguità nella fonte dell'eccezione, che nella maggior parte dei casi può essere evitata con un buon design. La strutturazione della logica ben stratificata all'interno di try / tranne / infine generalmente rende la logica più robusta (meno soggetta a errori del programmatore) rispetto alla sporcizia del codice con if-check preventivi per ogni pezzo di codice consumante. Rende anche gli errori molto espliciti e consente ai programmatori che consumano l'opzione di gestirli direttamente.
Peter M. Elias,

64
La maggior parte delle lamentele di ambiguità qui sono semplicemente perché il codice di esempio è mal strutturato. L'unica cosa dentro try:dovrebbe essere il tentativo di accesso all'attributo; non c'è motivo di concludere anche l'esecuzione doStuff. Esistono tuttavia alcune possibilità di ambiguità: se si propertytratta di una proprietà calcolata anziché di un attributo semplice, la sua implementazione potrebbe aumentare AttributeErrorinternamente. Questo è il motivo per cui in quasi tutte le situazioni reali come questa, getattrè preferibile hasattro catturare AttributeError.
Carl Meyer,

485

Puoi usare hasattr()o catturare AttributeError, ma se vuoi davvero solo il valore dell'attributo con un valore predefinito se non c'è, l'opzione migliore è solo usare getattr():

getattr(a, 'property', 'default value')

14
Ciò risolve entrambi i problemi di cui sopra: a) l'ambiguità della fonte di un possibile AttributeError, b) preservare l'approccio EAFP.
Peter M. Elias,

6
È anche il 25% delle righe di codice. Sicuramente questa deve essere la soluzione migliore.
fatuhoku,

16
Questa è la soluzione migliore "se vuoi davvero solo il valore dell'attributo con un valore predefinito". Anche se credo che questo sia ciò che molte persone vogliono effettivamente quando affermano di voler rilevare la presenza di un attributo, l'OP ha effettivamente richiesto quest'ultimo, quindi è ragionevole che le risposte dirette a quella domanda (hasattr, AttributeError) siano elencate più in alto .
Carl Meyer,

41

Penso che quello che stai cercando sia hasattr . Tuttavia, consiglierei qualcosa di simile se si desidera rilevare le proprietà di Python :

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

Lo svantaggio è che vengono rilevati anche gli errori di attributo nel __get__codice delle proprietà .

Altrimenti, do-

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

Documenti: http://docs.python.org/library/functions.html
Avvertenza:
il motivo della mia raccomandazione è che hasattr non rileva le proprietà.
Link: http://mail.python.org/pipermail/python-dev/2005-December/058498.html


3
hasattrrileva le proprietà in generale bene. È solo che tratta di sollevare un'eccezione nella propertyfunzione -wrap come significato che non esiste tale attributo; il post della mailing list di Python collegato riguarda una proprietà che genera un'eccezione quando si tenta di accedervi. Per tutti gli scopi pratici, tale attributo non esiste, perché non produrrà mai un valore. Inoltre, hasattrelimina solo le eccezioni in generale su Py 3.1 e precedenti; in 3.2+, sopprime solo (sostituendo con Falsereturn) AttributeError.
ShadowRanger,

32

Secondo pydoc, hasattr (obj, prop) chiama semplicemente getattr (obj, prop) e cattura le eccezioni. Quindi, è altrettanto valido racchiudere l'accesso all'attributo con un'istruzione try e catturare AttributeError come usare hasattr () in anticipo.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value

2
Beh, hasattr in realtà può essere ottimizzato. Ad esempio con pypy.
odinho - Velmont,

6
+1. Questo è ancora più sicuro dell'uso hasattrquando si esegue l' SomeClassoverride __getattr__poiché hasattrcatturerà tutte le eccezioni in Python 2.x, non proprio AttributeErrorcome ci si aspetterebbe. Questo problema è stato risolto in Python 3.2: vedi la mia altra risposta per una semplice soluzione.
Martin Geisler,

24

Vorrei suggerire di evitare questo:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

L'utente @jpalecek lo ha menzionato: se si AttributeErrorverifica all'interno doStuff(), ci si perde.

Forse questo approccio è migliore:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)

13

A seconda della situazione, puoi verificare con isinstancequale tipo di oggetto hai, quindi utilizzare gli attributi corrispondenti. Con l'introduzione di classi di base astratte in Python 2.6 / 3.0, questo approccio è diventato anche molto più potente (sostanzialmente gli ABC consentono un modo più sofisticato di scrivere l'anatra).

Una situazione in cui ciò sarebbe utile sarebbe se due oggetti diversi hanno un attributo con lo stesso nome, ma con significato diverso. L'uso di solo hasattrpotrebbe quindi portare a strani errori.

Un bell'esempio è la distinzione tra iteratori e iterabili (vedi questa domanda). I __iter__metodi in un iteratore e in un iterabile hanno lo stesso nome ma sono semanticamente abbastanza diversi! Quindi hasattrè inutile, ma isinstanceinsieme a ABC fornisce una soluzione pulita.

Tuttavia, concordo sul fatto che nella maggior parte dei casi l' hasattrapproccio (descritto in altre risposte) è la soluzione più appropriata.


13

Spero che ti aspetti hasattr (), ma cerca di evitare hasattr () e preferisci getattr (). getattr () è più veloce di hasattr ()

usando hasattr ():

 if hasattr(a, 'property'):
     print a.property

stesso qui sto usando getattr per ottenere proprietà se non c'è proprietà che non restituisce nessuno

   property = getattr(a,"property",None)
    if property:
        print property

11

EDIT : questo approccio ha serie limitazioni. Dovrebbe funzionare se l'oggetto è iterabile . Si prega di controllare i commenti qui sotto.

Se stai usando Python 3.6 o versioni successive come me, c'è una comoda alternativa per verificare se un oggetto ha un attributo particolare:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

Tuttavia, non sono sicuro di quale sia l'approccio migliore in questo momento. usando hasattr(), usando getattr()o usando in. I commenti sono ben accetti


6
inla parola chiave funziona per verificare i tipi iterabili. Ad esempio, 'foo' in Nonegenera l'errore TypeError: argument of type 'NoneType' is not iterable. La correzione è verificare se il tipo è iterabile prima dell'uso in. Dopo aver corretto i casi limite come il tipo non iterabile, probabilmente stai meglio usando hasattr()perché è progettato per gestire i casi limite.
Seth Difley,

3
Questo non ha nulla a che fare con l'accesso agli attributi. Non ho idea di come sia stato votato. L'unica somiglianza che deve attribuire l'accesso è se stai usando dictcome "oggetto leggero", simile al design degli oggetti JavaScript, ma la maggior parte delle classi normali non lo supporterà in generale (ottenendo una variante dell'errore menzionato da @SethDifley) .
ShadowRanger,


1

Questo è super semplice, basta usare l' dir(oggetto.)
Restituirà un elenco di tutte le funzioni e gli attributi disponibili dell'oggetto.


1

Un'altra possibile opzione, ma dipende da cosa intendi prima :

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

produzione:

bar:1
zoom!

Ciò consente di verificare anche la presenza di attributi con valore Nessuno.

Ma! Fai molta attenzione a non istanziare e confrontare accidentalmente undefinedpiù posti perché isnon funzionerà mai in quel caso.

Aggiornare:

a causa di ciò di cui stavo avvertendo nel paragrafo precedente, con più indefiniti che non corrispondono mai, ho recentemente modificato leggermente questo schema:

undefined = NotImplemented

NotImplemented, da non confondere NotImplementedError, è un built-in: abbina l'intento di un JS undefinede puoi riutilizzare la sua definizione ovunque e corrisponderà sempre. Lo svantaggio è che è "veritiero" nei booleani e può apparire strano nei registri e nelle tracce dello stack (ma lo si supera rapidamente quando si sa che appare solo in questo contesto).


0

È possibile verificare se objectcontiene l'attributo utilizzando il hasattrmetodo incorporato.

Ad esempio, se l'oggetto è ae si desidera verificare l'attributostuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

La stessa firma del metodo è hasattr(object, name) -> boolche significa se objectha un attributo che viene passato al secondo argomento in hasattrquanto fornisce un valore booleano Trueo in Falsebase alla presenza namedell'attributo nell'oggetto.


0

hasattr()è la risposta giusta. Quello che voglio aggiungere è che hasattr()può anche essere usato bene insieme a assert (per evitare ifdichiarazioni non necessarie e rendere il codice più leggibile):

assert hasattr(a, 'property'), 'object lacks property' 

Come affermato in un'altra risposta su SO : gli asserti dovrebbero essere usati per testare condizioni che non dovrebbero mai accadere. Lo scopo è quello di arrestarsi in anticipo nel caso di uno stato di programma corrotto.


Questo è utile ma potrebbe non essere sempre il caso. Forse volevo verificare se l'oggetto ha una proprietà e quindi aggiungerlo per la prima volta, o forse devo eseguire codice diverso per gli oggetti con quella proprietà. Quando il codice non può continuare, l'affermazione potrebbe andare bene. Ma ancora una volta, non è sempre il caso. L'importante è l'uso del hasattrcodice non circostante.
Lucas Gabriel Sánchez,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.