Cómo saber si un objeto tiene un atributo en Python

1635

¿Hay alguna manera en Python para determinar si un objeto tiene algún atributo? Por ejemplo:

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

¿Cómo puede saber si atiene el atributo propertyantes de usarlo?

Lucas Gabriel Sánchez
fuente

Respuestas:

2343

Prueba hasattr():

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

EDITAR: Vea la respuesta de zweiterlinde a continuación, ¡que ofrece buenos consejos sobre pedir perdón! ¡Un enfoque muy pitónico!

La práctica general en python es que, si es probable que la propiedad esté allí la mayor parte del tiempo, simplemente llámela y deje que la excepción se propague o atrape con un bloque try / except. Esto probablemente será más rápido que hasattr. Si es probable que la propiedad no esté allí la mayor parte del tiempo, o no está seguro, el uso hasattrprobablemente será más rápido que caer repetidamente en un bloque de excepción.

Jarret Hardie
fuente
19
Parece estar trabajando para verificar las funciones en el espacio de nombres también, por ejemplo: import string hasattr(string, "lower")
riviera
15
hasattres exactamente lo mismo que usar try/ except AttributeError: la cadena de documentación de hasattr (en Python 2.7) dice que usa excepciones de captura manual de getattr.
Jeff Tratner
8
@JeffTratner: hasattrlamentablemente no es exactamente lo mismo que try: ... except AttributeError:en Python 2.x ya hasattrque detectará todas las excepciones . Consulte mi respuesta para ver un ejemplo y una solución simple.
Martin Geisler
632

Como respondió Jarret Hardie , hasattrhará el truco. Sin embargo, me gustaría agregar que muchos en la comunidad de Python recomiendan una estrategia de "más fácil pedir perdón que permiso" (EAFP) en lugar de "mirar antes de saltar" (LBYL). Ver estas referencias:

EAFP vs LBYL (estaba Re: un poco decepcionado hasta el momento)
EAFP vs LBYL @Code Like a Pythonista: Idiomatic Python

es decir:

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

... se prefiere a:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()
zweiterlinde
fuente
259
Pero, ¿cómo verifica que fue la propiedad a.la que causó AttributeError, y no algo en doStuff ()? Parece que no lo haces. Creo que es realmente más fácil pedir perdón, pero muchas veces también es incorrecto.
jpalecek
286
EAFP parece ... demente. HasAttr envía telégrafos a futuros programadores de mantenimiento que estás verificando para un atributo particular. Obtener una excepción no les dice nada a los futuros programadores y podría conducir a alguien por el agujero del conejo.
Ethan Heilman
74
@ e5: tiene un punto justo en este caso, pero en muchos casos EAFP es la única opción correcta. Por ejemplo, si verifica la existencia de un archivo y luego lo abre, esperando que definitivamente exista, su código es incorrecto: el archivo puede ser eliminado o renombrado entre la verificación y el uso. Esto se llama un error TOCTOU (tiempo de verificación hasta el momento de uso) y, además de causar bloqueos, también puede ser una fuente de vulnerabilidades de seguridad.
Max
15
@EthanHeilman solo es una locura cuando existe una ambigüedad en la fuente de la excepción, que se puede evitar con un buen diseño en la mayoría de los casos. La estructuración lógica bien organizada dentro de try / except / finalmente generalmente proporciona una lógica más robusta (menos propensa a errores de programador) que ensuciar el código con verificaciones preventivas para cada pieza de código consumidor. También hace que los errores sean muy explícitos y permite a los programadores consumidores la opción de tratarlos directamente.
Peter M. Elias
64
La mayoría de las quejas de ambigüedad aquí son simplemente porque el código de muestra está mal estructurado. Lo único dentro de esto try:debería ser el intento de acceso al atributo; no hay razón para concluir la ejecución doStufftambién. Sin embargo, aún existe cierto potencial de ambigüedad: si se propertytrata de una propiedad calculada en lugar de un atributo simple, su implementación podría aumentar AttributeErrorinternamente. Es por eso que en casi todas las situaciones reales como esta, getattres preferible a cualquiera hasattro atrapar AttributeError.
Carl Meyer
485

Puede usar hasattr()o capturar AttributeError, pero si realmente solo desea el valor del atributo con un valor predeterminado si no está allí, la mejor opción es simplemente usar getattr():

getattr(a, 'property', 'default value')
Carl Meyer
fuente
14
Esto resuelve los dos problemas antes mencionados: a) La ambigüedad de la fuente de un posible AttributeError, b) Preservar el enfoque EAFP.
Peter M. Elias
66
También es el 25% de las líneas de código. Seguramente esta tiene que ser la mejor solución.
fatuhoku
16
Esta es la mejor solución "si realmente solo desea el valor del atributo con un valor predeterminado". Aunque creo que esto es lo que muchas personas realmente quieren cuando dicen que quieren detectar si un atributo está presente, el OP realmente solicitó el último, por lo que es razonable que las respuestas directas a esa pregunta (hasattr, AttributeError) aparezcan más arriba .
Carl Meyer
41

Creo que lo que estás buscando es hasattr . Sin embargo, recomendaría algo como esto si desea detectar las propiedades de Python :

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

La desventaja aquí es que los errores de atributo en el __get__código de propiedades también se detectan.

De lo contrario, haga

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

Documentos: http://docs.python.org/library/functions.html
Advertencia:
El motivo de mi recomendación es que hasattr no detecta propiedades.
Enlace: http://mail.python.org/pipermail/python-dev/2005-December/058498.html

Batbrat
fuente
3
hasattrdetecta propiedades en general muy bien. Es solo que trata de generar una excepción en la propertyfunción envuelta como si no existiera dicho atributo; la publicación de la lista de correo de Python vinculada trata sobre una propiedad que genera una excepción cuando intenta acceder a ella. Para todos los propósitos prácticos, dicho atributo no existe, porque nunca producirá un valor. Además, hasattrsolo suprime las excepciones en general en Py 3.1 y anteriores; en 3.2+, solo suprime (reemplazando con Falsereturn) AttributeError.
ShadowRanger
32

Según pydoc, hasattr (obj, prop) simplemente llama a getattr (obj, prop) y captura excepciones. Por lo tanto, es tan válido envolver el acceso al atributo con una instrucción try y atrapar AttributeError como usar hasattr () de antemano.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value
Jordan Lewis
fuente
2
Bueno, hasattr en realidad puede estar optimizado. Por ejemplo, con pypy.
Odinho - Velmont
66
+1. Esto es incluso más seguro que usarlo hasattrcuando se SomeClassanula, __getattr__ya hasattrque detectará todas las excepciones en Python 2.x, no solo AttributeErrorcomo es de esperar. Esto se solucionó en Python 3.2: consulte mi otra respuesta para una solución simple.
Martin Geisler
24

Me gustaría sugerir evitar esto:

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

El usuario @jpalecek lo mencionó: si AttributeErrorocurre algo dentro doStuff(), está perdido.

Quizás este enfoque sea mejor:

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

Dependiendo de la situación, puede verificar con isinstancequé tipo de objeto tiene, y luego usar los atributos correspondientes. Con la introducción de clases base abstractas en Python 2.6 / 3.0, este enfoque también se ha vuelto mucho más poderoso (básicamente, los ABC permiten una forma más sofisticada de tipear patos).

Una situación en la que esto es útil sería si dos objetos diferentes tienen un atributo con el mismo nombre, pero con un significado diferente. Usar solo hasattrpodría provocar errores extraños.

Un buen ejemplo es la distinción entre iteradores e iterables (vea esta pregunta). ¡Los __iter__métodos en un iterador y un iterable tienen el mismo nombre pero son semánticamente bastante diferentes! Por hasattrlo tanto, es inútil, pero isinstancejunto con ABC proporciona una solución limpia.

Sin embargo, estoy de acuerdo en que, en la mayoría de las situaciones, el hasattrenfoque (descrito en otras respuestas) es la solución más adecuada.

nikow
fuente
13

Espero que esperes hasattr (), pero trata de evitar hasattr () y prefiere getattr (). getattr () es más rápido que hasattr ()

usando hasattr ():

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

lo mismo aquí estoy usando getattr para obtener propiedad si no hay ninguna propiedad, no devuelve ninguna

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

EDITAR : Este enfoque tiene serias limitaciones. Debería funcionar si el objeto es iterable . Por favor revise los comentarios a continuación.

Si está utilizando Python 3.6 o superior como yo, existe una alternativa conveniente para verificar si un objeto tiene un atributo particular:

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

Sin embargo, no estoy seguro de cuál es el mejor enfoque en este momento. usando hasattr(), usando getattr()o usando in. Comentarios son bienvenidos

nayak
fuente
66
inla palabra clave funciona para verificar tipos iterables. Por ejemplo, 'foo' in Nonearroja el error TypeError: argument of type 'NoneType' is not iterable. La solución es verificar si el tipo es iterable antes de usarlo in. Después de corregir casos extremos como el tipo no iterable, probablemente sea mejor usarlo hasattr()porque está diseñado para manejar los casos extremos.
Seth Difley
3
Esto no tiene nada que ver con el acceso a atributos. No tengo idea de cómo se votó. La única similitud que tiene para atribuir el acceso es si está utilizando dictun "objeto ligero", similar al diseño de objetos JavaScript, pero la mayoría de las clases normales no admitirán esto en general (obteniendo una variante del error mencionado por @SethDifley) .
ShadowRanger
6

Aquí hay un enfoque muy intuitivo:

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

Esto es súper simple, solo use dir(object)
Esto devolverá una lista de todas las funciones y atributos disponibles del objeto.

Sean cristianos
fuente
1

Otra opción posible, pero depende de a qué te refieres antes :

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

salida:

bar:1
zoom!

Esto le permite incluso verificar los atributos sin valor.

¡Pero! Tenga mucho cuidado de no crear instancias accidentalmente y comparar undefinedvarios lugares porque isnunca funcionará en ese caso.

Actualizar:

Debido a lo que estaba advirtiendo en el párrafo anterior, al tener múltiples indefinidos que nunca coinciden, recientemente he modificado ligeramente este patrón:

undefined = NotImplemented

NotImplemented, que no debe confundirse con NotImplementedError, es una función incorporada: coincide con la intención de un JS undefinedy puede reutilizar su definición en todas partes y siempre coincidirá. El inconveniente es que es "verdadero" en los booleanos y puede verse raro en los registros y los rastros de la pila (pero lo superas rápidamente cuando sabes que solo aparece en este contexto).

JL Peyret
fuente
0

Puede verificar si objectcontiene un atributo utilizando el hasattrmétodo incorporado.

Por ejemplo, si su objeto es ay desea verificar el atributostuff

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

La firma del método en sí es lo hasattr(object, name) -> boolque significa si objecttiene un atributo que se pasa al segundo argumento en lugar hasattrde lo que da booleano Trueo de Falseacuerdo con la presencia del nameatributo en el objeto.

Devang Padhiyar
fuente
0

hasattr()es la respuesta correcta Lo que quiero agregar es que hasattr()también se puede usar bien junto con afirmar (para evitar ifdeclaraciones innecesarias y hacer que el código sea más legible):

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

Como se indicó en otra respuesta sobre SO : Las afirmaciones deben usarse para probar condiciones que nunca deberían suceder. El propósito es colapsar temprano en el caso de un estado corrupto del programa.

FMF
fuente
Esto es útil, pero puede no ser siempre el caso. Tal vez quería probar si el objeto tiene una propiedad y luego agregarlo por primera vez, o tal vez tengo que ejecutar un código diferente para los objetos con esa propiedad. Cuando el código no puede continuar, la afirmación puede estar bien. Pero de nuevo, no siempre es el caso. Lo importante es el uso de hasattrno el código circundante.
Lucas Gabriel Sánchez