Comment savoir si un objet a un attribut en Python

1635

Existe-t-il un moyen en Python pour déterminer si un objet a un attribut? Par exemple:

>>> 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'

Comment savoir si aa l'attribut propertyavant de l'utiliser?

Lucas Gabriel Sánchez
la source

Réponses:

2343

Essayez hasattr():

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

EDIT: Voir la réponse de zweiterlinde ci-dessous, qui offre de bons conseils pour demander pardon! Une approche très pythonique!

La pratique générale en python est que, si la propriété est susceptible d'être là la plupart du temps, il suffit de l'appeler et de laisser l'exception se propager, ou de la piéger avec un bloc try / except. Ce sera probablement plus rapide que hasattr. Si la propriété n'est probablement pas là la plupart du temps, ou si vous n'êtes pas sûr, l'utilisation hasattrsera probablement plus rapide que de tomber à plusieurs reprises dans un bloc d'exception.

Jarret Hardie
la source
19
Semble également fonctionner pour vérifier les fonctions dans l'espace de noms, par exemple: import string hasattr(string, "lower")
riviera
15
hasattrest exactement la même chose que l'utilisation de try/ except AttributeError: la docstring de hasattr (en Python 2.7) indique qu'elle utilise des exceptions de capture de main getattr.
Jeff Tratner
8
@JeffTratner: hasattrn'est malheureusement pas exactement le même que try: ... except AttributeError:dans Python 2.x car hasattril interceptera toutes les exceptions . Veuillez consulter ma réponse pour un exemple et une solution de contournement simple.
Martin Geisler
632

Comme Jarret Hardie a répondu, hasattrfera l'affaire. Je voudrais cependant ajouter que de nombreux membres de la communauté Python recommandent une stratégie «plus facile de demander pardon que permission» (EAFP) plutôt que de «regarder avant de sauter» (LBYL). Voir ces références:

EAFP vs LBYL (était Re: Un peu déçu jusqu'à présent)
EAFP vs LBYL @Code Like a Pythonista: Idiomatic Python

c'est à dire:

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

... est préféré à:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()
zweiterlinde
la source
259
Mais comment vérifiez-vous que c'est la propriété a.property qui a causé AttributeError, et non quelque chose dans doStuff ()? Il semble que non. Je pense qu'il est vraiment plus facile de demander pardon, mais souvent, c'est également incorrect.
jpalecek le
286
L'EAFP semble ... fou. HasAttr télégraphie aux futurs programmeurs de maintenance que vous recherchez un attribut particulier. Obtenir une exception ne dit rien aux futurs programmeurs et pourrait conduire quelqu'un dans le terrier du lapin.
Ethan Heilman
74
@ e5: vous avez un bon point dans ce cas, mais dans de nombreux cas, EAFP est la seule option correcte. Par exemple, si vous vérifiez l'existence d'un fichier, puis l'ouvrez, en espérant qu'il existera définitivement, votre code est incorrect: le fichier peut être supprimé ou renommé entre la vérification et l'utilisation. C'est ce qu'on appelle une erreur TOCTOU (Time-Of-Check-To-Time-Of-Use) et en plus de provoquer des plantages peut également être une source de failles de sécurité.
Max
15
@EthanHeilman, c'est fou quand il y a une ambiguïté dans la source de l'exception, ce qui peut être évité avec un bon design dans la plupart des cas. Une bonne structuration de la logique dans try / except / finalement rend généralement la logique plus robuste (moins sujette aux erreurs du programmeur) que de surcharger le code avec des if-checks préemptifs pour chaque morceau de code consommant. Rend également les erreurs très explicites et permet aux programmeurs consommateurs de les traiter directement.
Peter M. Elias
64
La plupart des plaintes d'ambiguïté ici sont simplement dues au fait que l'exemple de code est mal structuré. La seule chose à l'intérieur du try:devrait être la tentative d'accès aux attributs; il n'y a aucune raison de boucler également l'exécution de doStuff. Il existe cependant un certain potentiel d'ambiguïté: s'il propertys'agit d'une propriété calculée au lieu d'un attribut simple, son implémentation pourrait augmenter en AttributeErrorinterne. C'est pourquoi dans presque toutes les situations réelles comme celle-ci, getattrest préférable à l'un hasattrou à l'autre AttributeError.
Carl Meyer
485

Vous pouvez utiliser hasattr()ou attraper AttributeError, mais si vous voulez vraiment juste la valeur de l'attribut avec un défaut s'il n'est pas là, la meilleure option est simplement d'utiliser getattr():

getattr(a, 'property', 'default value')
Carl Meyer
la source
14
Cela résout les deux problèmes susmentionnés: a) l'ambiguïté de la source d'une éventuelle erreur d'attribut, b) la préservation de l'approche EAFP.
Peter M. Elias
6
C'est aussi 25% des lignes de code. Cela doit sûrement être la meilleure solution.
fatuhoku
16
C'est la meilleure solution "si vous voulez vraiment juste la valeur de l'attribut avec un défaut". Bien que je pense que c'est ce que beaucoup de gens veulent réellement quand ils disent qu'ils veulent détecter si un attribut est présent, l'OP a en fait demandé ce dernier, il est donc raisonnable que les réponses directes à cette question (hasattr, AttributeError) soient répertoriées plus haut .
Carl Meyer
41

Je pense que ce que vous recherchez est hasattr . Cependant, je recommanderais quelque chose comme ça si vous voulez détecter les propriétés de python -

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

L'inconvénient ici est que les erreurs d'attribut dans le __get__code de propriétés sont également détectées.

Sinon, faites-

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

Docs: http://docs.python.org/library/functions.html
Avertissement:
La raison de ma recommandation est que hasattr ne détecte pas les propriétés.
Lien: http://mail.python.org/pipermail/python-dev/2005-December/058498.html

batbrat
la source
3
hasattrdétecte très bien les propriétés en général. C'est juste qu'il traite de lever une exception dans la propertyfonction -wrapped comme signifiant qu'aucun tel attribut n'existe; la publication de liste de diffusion Python liée concerne une propriété qui déclenche une exception lorsque vous essayez d'y accéder. À toutes fins pratiques, cet attribut n'existe pas, car il ne produira jamais de valeur. En outre, hasattrsupprime uniquement les exceptions en général sur Py 3.1 et versions antérieures; dans 3.2+, il supprime seulement (en remplaçant par Falsereturn) AttributeError.
ShadowRanger
32

Selon pydoc, hasattr (obj, prop) appelle simplement getattr (obj, prop) et intercepte les exceptions. Ainsi, il est tout aussi valide d'envelopper l'accès aux attributs avec une instruction try et d'attraper AttributeError que d'utiliser auparavant hasattr ().

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value
Jordan Lewis
la source
2
Eh bien, hasattr peut en fait être optimisé. Par exemple avec du pavot.
odinho - Velmont
6
+1. C'est encore plus sûr que d'utiliser hasattrlors des SomeClassremplacements, __getattr__car toutes les exceptions en Python 2.x hasattrseront capturées, pas exactement comme vous vous y attendriez. Cela a été corrigé dans Python 3.2 - veuillez consulter mon autre réponse pour une solution de contournement simple. AttributeError
Martin Geisler
24

Je voudrais suggérer d'éviter cela:

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

L'utilisateur @jpalecek l'a mentionné: Si un AttributeErrorse produit à l'intérieur doStuff(), vous êtes perdu.

Peut-être que cette approche est meilleure:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)
Maico
la source
13

Selon la situation, vous pouvez vérifier avec isinstancequel type d'objet vous disposez, puis utiliser les attributs correspondants. Avec l'introduction de classes de base abstraites dans Python 2.6 / 3.0, cette approche est également devenue beaucoup plus puissante (les ABC permettent essentiellement une manière plus sophistiquée de taper du canard).

Une situation où cela est utile serait si deux objets différents ont un attribut avec le même nom, mais avec une signification différente. Utiliser uniquement hasattrpeut alors conduire à des erreurs étranges.

Un bel exemple est la distinction entre les itérateurs et les itérables (voir cette question). Les __iter__méthodes d'un itérateur et d'un itérable ont le même nom mais sont sémantiquement assez différentes! hasattrEst donc inutile, mais isinstanceavec ABC fournit une solution propre.

Cependant, je conviens que dans la plupart des situations, l' hasattrapproche (décrite dans d'autres réponses) est la solution la plus appropriée.

nikow
la source
13

J'espère que vous attendez hasattr (), mais essayez d'éviter hasattr () et préférez getattr (). getattr () est plus rapide que hasattr ()

en utilisant hasattr ():

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

même ici, j'utilise getattr pour obtenir une propriété s'il n'y a pas de propriété, il ne retourne aucun

   property = getattr(a,"property",None)
    if property:
        print property
Janarthanan Ramu
la source
11

EDIT : Cette approche a de sérieuses limites. Cela devrait fonctionner si l'objet est itérable . Veuillez vérifier les commentaires ci-dessous.

Si vous utilisez Python 3.6 ou supérieur comme moi, il existe une alternative pratique pour vérifier si un objet a un attribut particulier:

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

Cependant, je ne sais pas quelle est la meilleure approche en ce moment. en utilisant hasattr(), en utilisant getattr()ou en utilisant in. Les commentaires sont les bienvenus.

nayak
la source
6
inLe mot clé fonctionne pour vérifier les types itérables. Par exemple, 'foo' in Nonejette l'erreur TypeError: argument of type 'NoneType' is not iterable. Le correctif consiste à vérifier si le type est itérable avant utilisation in. Après avoir corrigé les cas de bord comme le type non itérable, il est probablement préférable d'utiliser hasattr()car il est conçu pour gérer les cas de bord.
Seth Difley
3
Cela n'a rien à voir avec l'accès aux attributs. Je ne sais pas comment cela a été voté. La seule similitude dont il dispose pour attribuer l'accès est si vous l'utilisez dictcomme un "objet léger", similaire à la conception d'objets JavaScript, mais la plupart des classes normales ne prendront pas en charge cela en général (obtenir une variante de l'erreur mentionnée par @SethDifley) .
ShadowRanger
6

Voici une approche très intuitive:

if 'property' in dir(a):
    a.property
Alec Alameddine
la source
1

C'est super simple, il suffit d'utiliser l' dir(objet)
Cela retournera une liste de toutes les fonctions et attributs disponibles de l'objet.

Sean Christians
la source
1

Une autre option possible, mais cela dépend de ce que vous entendez par avant :

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()

production:

bar:1
zoom!

Cela vous permet même de vérifier les attributs sans valeur.

Mais! Faites très attention de ne pas instancier accidentellement et de comparer undefinedplusieurs endroits car iscela ne fonctionnera jamais dans ce cas.

Mise à jour:

à cause de ce que j'avertissais dans le paragraphe ci-dessus, ayant plusieurs indéfinis qui ne correspondent jamais, j'ai récemment légèrement modifié ce modèle:

undefined = NotImplemented

NotImplemented, à ne pas confondre avec NotImplementedError, est un intégré: il correspond semi à l'intention d'un JS undefinedet vous pouvez réutiliser sa définition partout et il correspondra toujours. L'inconvénient est qu'il est "véridique" chez les booléens et qu'il peut paraître bizarre dans les journaux et les traces de pile (mais vous vous en remettez rapidement lorsque vous savez qu'il n'apparaît que dans ce contexte).

JL Peyret
la source
0

Vous pouvez vérifier si objectcontient un attribut à l'aide de la hasattrméthode intégrée.

Pour une instance si votre objet est aet que vous souhaitez vérifier l'attributstuff

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

La signature de la méthode elle-même est hasattr(object, name) -> boolce qui signifie si objecta un attribut qui est passé au deuxième argument dans hasattrce qu'il donne booléen Trueou Falseselon la présence d' nameattribut dans l'objet.

Devang Padhiyar
la source
0

hasattr()est la bonne réponse. Ce que je veux ajouter, c'est que cela hasattr()peut également être bien utilisé en conjonction avec assert (pour éviter les ifinstructions inutiles et rendre le code plus lisible):

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

Comme indiqué dans une autre réponse sur SO : les assertions doivent être utilisées pour tester des conditions qui ne devraient jamais se produire. Le but est de planter tôt dans le cas d'un état de programme corrompu.

FMF
la source
C'est utile mais ce n'est pas toujours le cas. Peut-être que je voulais tester si l'objet a une propriété, puis l'ajouter pour la première fois, ou peut-être que je dois exécuter un code différent pour les objets avec cette propriété. Lorsque le code ne peut pas continuer, l'assertion peut être correcte. Mais encore une fois, ce n'est pas toujours le cas. L'important est d'utiliser hasattrnon pas le code environnant.
Lucas Gabriel Sánchez