python isinstance vs hasattr vs try/except: ¿Qué es mejor?
exception-handling attributes (3)
La comprobación con isinstance
va en contra de la convención de Python de utilizar el tipado de pato .
hasattr
funciona bien, pero es Look Before You Leap en lugar del Pythonic EAFP .
La implementación del modo 3 es peligrosa, ya que do_stuff
todos los errores, incluidos los que plantea el método do_stuff
. Podrías ir con el más preciso:
try:
_ds = obj.do_stuff
except AttributeError:
print(''Do something else'')
else:
_ds()
Pero en este caso, preferiría el modo 2 a pesar de la ligera sobrecarga, es mucho más legible.
Estoy tratando de averiguar las compensaciones entre los diferentes enfoques para determinar si obj
puede o no realizar la acción do_stuff()
. Según tengo entendido, hay tres formas de determinar si esto es posible:
# Way 1
if isinstance(obj, Foo):
obj.do_stuff()
# Way 2
if hasattr(obj, ''do_stuff''):
obj.do_stuff()
# Way 3
try:
obj.do_stuff()
except:
print ''Do something else''
¿Cuál es el método preferido (y por qué)?
Creo que el último método es generalmente preferido por los codificadores de Python debido a un lema enseñado en la comunidad de Python: "Es más fácil pedir perdón que permiso" (EAFP).
En pocas palabras, el lema significa evitar comprobar si puede hacer algo antes de hacerlo. En cambio, simplemente ejecuta la operación. Si falla, manejarlo apropiadamente.
Además, el tercer método tiene la ventaja adicional de dejar en claro que la operación debería funcionar.
Dicho esto, deberías evitar usar un bare, except
así. Al hacerlo, se capturarán todas las excepciones, incluso las no relacionadas. En cambio, es mejor capturar excepciones específicamente.
Aquí, querrá capturar para un AttributeError
:
try:
obj.do_stuff() # Try to invoke do_stuff
except AttributeError:
print ''Do something else'' # If unsuccessful, do something else
La respuesta correcta es ''ninguno''. Hasattr ofrece funcionalidad, pero posiblemente sea la peor de todas las opciones.
Usamos la naturaleza orientada a objetos de python porque funciona. El análisis OO nunca es preciso ya menudo confunde, sin embargo, usamos jerarquías de clase porque sabemos que ayudan a las personas a hacer un mejor trabajo más rápido. La gente capta objetos y un buen modelo de objetos ayuda a los codificadores a cambiar las cosas más rápidamente y con menos errores. El código correcto termina agrupado en los lugares correctos. Los objetos:
- Solo se puede usar sin considerar qué implementación está presente
- Dejar en claro lo que se debe cambiar y dónde
- Aísle los cambios de algunas funcionalidades de los cambios a alguna otra funcionalidad; puede reparar X sin temor a que rompa Y
hasattr vs isinstance
Tener que usar isinstance o hasattr en absoluto indica que el modelo de objeto está roto o que lo estamos usando incorrectamente. Lo correcto es corregir el modelo de objeto o cambiar cómo lo estamos usando. Estos dos constructos tienen el mismo efecto y en el sentido imperativo "Necesito el código para hacer esto" son equivalentes. Estructuralmente hay una gran diferencia. Al cumplir con este método por primera vez (o después de algunos meses de hacer otras cosas), isinstance transmite una gran cantidad de información sobre lo que realmente está sucediendo y qué más es posible. Hasattr no te dice nada.
Una larga historia de desarrollo nos aleja de FORTRAN y el código con un montón de interruptores "¿quién soy yo?". Elegimos usar objetos porque sabemos que ayudan a que el código sea más fácil de usar. Al elegir hasattr entregamos funcionalidad, sin embargo, nada es fijo, el código está más roto de lo que era antes de que comenzáramos. Al agregar o cambiar esta funcionalidad en el futuro, tendremos que tratar con un código que está desigualmente agrupado y tiene al menos dos principios de organización, algunos de ellos es donde debería ''estar'' y el resto está disperso aleatoriamente en otros lugares. No hay nada que lo haga coherente. Este no es un error sino un campo minado de posibles errores dispersos en cualquier ruta de ejecución que pase por su hasattr.
Entonces, si hay alguna opción, el orden es:
- Usa el modelo de objetos o arréglelo o al menos averigüe qué está mal con él y cómo solucionarlo
- Use isinstance
- No use hasattr