No existe la "mejor" manera, porque nunca se está simplemente comprobando si existe un atributo; siempre es parte de un programa más grande. Hay varias formas correctas y una notable manera incorrecta.
El camino equivocado
if 'property' in a.__dict__:
a.property
Aquí es una demostración que muestra esta técnica en su defecto:
class A(object):
@property
def prop(self):
return 3
a = A()
print "'prop' in a.__dict__ =", 'prop' in a.__dict__
print "hasattr(a, 'prop') =", hasattr(a, 'prop')
print "a.prop =", a.prop
Salida:
'prop' in a.__dict__ = False
hasattr(a, 'prop') = True
a.prop = 3
mayor parte del tiempo, que no quieren meterse con __dict__
. Es un atributo especial para hacer cosas especiales, y verificar si existe un atributo es bastante mundano.
El EAFP manera
Un idioma común en Python es "más fácil pedir perdón que pedir permiso", o EAFP para abreviar. Verá un montón de código Python que usa este modismo, y no solo para verificar la existencia de atributos.
# Cached attribute
try:
big_object = self.big_object
# or getattr(self, 'big_object')
except AttributeError:
# Creating the Big Object takes five days
# and three hundred pounds of over-ripe melons.
big_object = CreateBigObject()
self.big_object = big_object
big_object.do_something()
Tenga en cuenta que esta es exactamente la misma expresión idiomática para abrir un archivo que puede no existir.
try:
f = open('some_file', 'r')
except IOError as ex:
if ex.errno != errno.ENOENT:
raise
# it doesn't exist
else:
# it does and it's open
Además, para convertir cadenas en números enteros.
try:
i = int(s)
except ValueError:
print "Not an integer! Please try again."
sys.exit(1)
Incluso la importación de módulos opcionales ...
try:
import readline
except ImportError:
pass
La forma LBYL
El método hasattr
, por supuesto, también funciona. Esta técnica se llama "mirar antes de saltar", o LBYL para abreviar.
# Cached attribute
if not hasattr(self, 'big_object'):
big_object = CreateBigObject()
self.big_object = CreateBigObject()
big_object.do_something()
(La orden interna hasattr
realidad comporta de forma extraña en las versiones de Python anteriores a 3.2 en relación con excepciones - que capturar las excepciones que no debería -. Pero esto es probablemente irrelevante, ya que es poco probable que tales excepciones El La técnica hasattr
también es más lenta que try/except
, pero no la llama con la frecuencia suficiente para importar y la diferencia no es muy grande. Finalmente, hasattr
no es atómico, por lo que podría arrojar AttributeError
si otro hilo elimina el atributo, pero esto es un escenario exagerado y deberá tener mucho cuidado con los hilos de todos modos. No creo que valga la pena preocuparse por ninguna de estas tres diferencias.)
El uso de hasattr
es mucho más simple que try/except
, siempre que lo único que necesite saber es si el atributo existe. El gran problema para mí es que la técnica LBYL parece "extraña", ya que como programador de Python estoy más acostumbrado a leer la técnica EAFP. Si reescribe los ejemplos anteriores para que utilicen el estilo LBYL
, obtendrá un código que es torpe, francamente incorrecto o demasiado difícil de escribir.
# Seems rather fragile...
if re.match('^(:?0|-?[1-9][0-9]*)$', s):
i = int(s)
else:
print "Not an integer! Please try again."
sys.exit(1)
Y LBYL veces es pura y simple incorrecto:
if os.path.isfile('some_file'):
# At this point, some other program could
# delete some_file...
f = open('some_file', 'r')
Si desea escribir una función LBYL para la importación de módulos opcionales, adelante ... que suena como la función sería todo un monstruo .
La forma getattr
Si sólo tiene un valor por defecto, getattr
es una versión más corta de try/except
.
x = getattr(self, 'x', default_value)
Si el valor predeterminado es caro de construir, entonces usted va a terminar con algo como esto:
x = getattr(self, 'attr', None)
if x is None:
x = CreateDefaultValue()
self.attr = x
O si None
es un valor posible,
sentinel = object()
x = getattr(self, 'attr', sentinel)
if x is sentinel:
x = CreateDefaultValue()
self.attr = x
Conclusión
Internamente, getattr
y hasattr
builtins solo use la técnica try/except
(excepto lo escrito en C). Entonces todos se comportan de la misma manera en lo que cuenta, y elegir el correcto se debe a una cuestión de circunstancias y estilo.
El código EAFP try/except
siempre frotará algunos programadores de la manera incorrecta, y el código hasattr/getattr
LBYL irritará a otros programadores. Ambos son correctos, y a menudo no hay una razón realmente convincente para elegir uno o el otro. (Sin embargo, otros programadores están disgustados que usted consideraría normal que un atributo a ser indefinido, y algunos programadores están horrorizados de que es posible tener un atributo definido en Python.)
La segunda opción es malo, de todos modos la [segunda respuesta] (http://stackoverflow.com/a/610923/1132524) desde el enlace que ya ha proporcionado respuesta a su pregunta. –