¿Hay alguna forma de saber (en el momento de la codificación) qué excepciones esperar al ejecutar el código python? Terminé atrapando la clase de excepción base el 90% del tiempo ya que no sé qué tipo de excepción podría arrojarse (y no me pidas que lea la documentación. Muchas veces se puede propagar una excepción desde la profundidad. muchas veces la documentación no está actualizada o es correcta). ¿Hay algún tipo de herramienta para verificar esto? (como leyendo el código python y libs)?Python: ¿Cómo puedo saber qué excepciones se pueden lanzar desde un método? Llame al
Respuesta
supongo que una solución podría ser la única imprecisa debido a la falta de reglas tipos estáticos.
No conozco alguna herramienta que verifique las excepciones, pero podría encontrar su propia herramienta que coincida con sus necesidades (una buena oportunidad para jugar un poco con el análisis estático).
En un primer intento, se podría escribir una función que construye un AST, encuentra todos los Raise
nodos, y luego trata de averiguar los patrones comunes de excepciones ganadería (por ejemplo, llamar a un constructor directamente)
Vamos x
ser el siguiente programa:
x = '''\
if f(x):
raise IOError(errno.ENOENT, 'not found')
else:
e = g(x)
raise e
'''
Construir la AST usando el paquete de compiler
:
tree = compiler.parse(x)
A continuación, defina una clase Raise
visitante:
class RaiseVisitor(object):
def __init__(self):
self.nodes = []
def visitRaise(self, n):
self.nodes.append(n)
y caminar por la recogida de AST Raise
nodos:
v = RaiseVisitor()
compiler.walk(tree, v)
>>> print v.nodes
[
Raise(
CallFunc(
Name('IOError'),
[Getattr(Name('errno'), 'ENOENT'), Const('not found')],
None, None),
None, None),
Raise(Name('e'), None, None),
]
Puede continuar resolviendo símbolos utilizando tablas de símbolos compilador, el análisis de dependencias de datos, etc. O puede simplemente deducir, que CallFunc(Name('IOError'), ...)
"definitivamente debe significar elevar IOError
", que está bastante bien para obtener resultados prácticos rápidos :)
Gracias por esta interesante respuesta. Aunque no entendí por qué debería buscar algo más aparte de todos los nodos de aumento. ¿Por qué debería "resolver símbolos usando tablas de símbolos de compilación, analizando dependencias de datos"? ¿No es la única forma de elevar la excepción de raise()? – GabiMe
Dado el valor 'v.nodes' anterior, no se puede decir realmente qué es 'Name ('IOError')' o 'Name ('e')'. No sabe a qué valor (s) pueden apuntar los 'IOError' y' e', ya que son las llamadas variables libres. Incluso si su contexto vinculante fuera conocido (aquí entran en juego las tablas de símbolos), debe realizar algún tipo de análisis de dependencia de datos para inferir sus valores exactos (esto debería ser difícil en Python). –
Como está buscando una solución práctica semiautomatizada, una lista de '['IOError (errno.ENOENT," not found ")', 'e']' que se muestra al usuario está bien.Pero no puede inferir clases reales de valores de variables representadas por cadenas :) (lo siento por reenviar) –
Solo debe detectar las excepciones que manejará.
La captura de todas las excepciones por sus tipos concretos no tiene sentido. Debería detectar las excepciones específicas que puede y manejarán. Para otras excepciones, puede escribir un catch genérico que capte "base Exception", lo registre (use la función str()
) y finalice su programa (o haga otra cosa que sea apropiada en una situación crashy).
Si realmente va a manejar todas las excepciones y estamos seguros de que ninguno de ellos son mortales (por ejemplo, si se está ejecutando el código en algún tipo de un entorno de espacio aislado), entonces su enfoque de la captura de BaseException genérica se adapte a su objetivos.
También te puede interesar language exception reference, no una referencia para la biblioteca que estás utilizando.
Si la referencia de la biblioteca es muy pobre y que no vuelva a lanzar sus propias excepciones al coger las de sistema, el único enfoque es útil para ejecutar pruebas (tal vez agregarlo al conjunto de pruebas, porque si algo es indocumentado , puede cambiar!). Elimine un archivo crucial para su código y verifique qué excepción se está lanzando. Suministre demasiados datos y compruebe qué error produce.
Tendrá que ejecutar pruebas de todos modos, ya que, incluso si existiera el método para obtener las excepciones por código fuente, no le daría ninguna idea de cómo debe manejar cualquiera de esos. Tal vez debería mostrar el mensaje de error "¡No se encuentra el archivo needful.txt!" cuando tomas IndexError
? Solo la prueba puede decir.
Claro, pero ¿cómo puede uno decidir qué excepciones debería manejar si no sabe lo que podría arrojarse? – GabiMe
@ bugspy.net, corrigió mi respuesta para reflejar este asunto –
Tal vez es hora de que el analizador de código fuente pueda averiguarlo. No debería ser demasiado difícil de desarrollar, creo que – GabiMe
Normalmente, debe detectar excepciones solo alrededor de unas pocas líneas de código. No querrá poner toda su función main
en la cláusula try except
. por cada pocas líneas que siempre debería (o puede verificar fácilmente) qué tipo de excepción podría surgir.
documentos tienen un exhaustivo list of built-in exceptions. no intente exceptuar aquellas excepciones que no espera, pueden ser manejadas/esperadas en el código de llamada.
editar: ¡lo que se arroje depende obviamente de lo que está haciendo! acceder al elemento aleatorio de una secuencia: IndexError
, elemento aleatorio de un dict: KeyError
, etc.
Simplemente intente ejecutar esas pocas líneas en IDLE y ocasione una excepción. Pero la prueba de unidad sería una mejor solución, naturalmente.
Esto no responde mi pregunta simple. No pregunto cómo diseñar mi manejo de excepciones, ni cuándo ni cómo atraparlo. Pregunto cómo averiguar qué podría arrojarse – GabiMe
@ bugspy.net: es ** imposible ** hacer lo que pide, y esta es una solución perfectamente válida. –
La herramienta correcta para resolver este problema es unittest. Si tiene excepciones planteadas por código real que los unittest no aumentan, entonces necesita más unittest.
consideran este
def f(duck):
try:
duck.quack()
except ??? could be anything
pato puede ser cualquier objeto
Obviamente se puede tener un AttributeError
si pato tiene ningún charlatán, un pato TypeError
si tiene un charlatán, pero no es exigible. No tienes idea de lo que podría plantear duck.quack()
sin embargo, tal vez incluso un DuckError
o algo
Ahora supongamos que tiene un código como éste
arr[i] = get_something_from_database()
Si se plantea una IndexError
no se sabe si ha venido de arr [i] o desde el interior de la función de la base de datos. Por lo general, no importa tanto dónde ocurrió la excepción, sino que algo salió mal y no sucedió lo que quería que sucediera.
Una técnica útil es atrapar y tal vez volver a subir la excepción como esta
except Exception as e
#inspect e, decide what to do
raise
¿Por qué atraparlo si va a "volver a publicarlo"? –
No tiene _ para volver a publicarlo, eso es lo que se suponía que el comentario indicaba. –
También puede optar por registrar la excepción en algún lugar y luego resubir –
me encontré con esto cuando el uso de zócalo, que quería encontrar una Todas las condiciones de error en las que me encontraría (así que en vez de tratar de crear errores y averiguar qué socket solo quería una lista concisa). En última instancia terminé grep'ing "/usr/lib64/python2.4/test/test_socket.py" para "levantar":
$ grep raise test_socket.py
Any exceptions raised by the clients during their tests
raise TypeError, "test_func must be a callable function"
raise NotImplementedError, "clientSetUp must be implemented."
def raise_error(*args, **kwargs):
raise socket.error
def raise_herror(*args, **kwargs):
raise socket.herror
def raise_gaierror(*args, **kwargs):
raise socket.gaierror
self.failUnlessRaises(socket.error, raise_error,
self.failUnlessRaises(socket.error, raise_herror,
self.failUnlessRaises(socket.error, raise_gaierror,
raise socket.error
# Check that setting it to an invalid value raises ValueError
# Check that setting it to an invalid type raises TypeError
def raise_timeout(*args, **kwargs):
self.failUnlessRaises(socket.timeout, raise_timeout,
def raise_timeout(*args, **kwargs):
self.failUnlessRaises(socket.timeout, raise_timeout,
que es una lista bastante concisa de errores. Ahora, por supuesto, esto solo funciona caso por caso y depende de que las pruebas sean precisas (que generalmente son). De lo contrario, es necesario capturar todas las excepciones, registrarlas y diseccionarlas y descubrir cómo manejarlas (lo que con las pruebas unitarias no sería demasiado difícil).
Esto fortalece mi argumento, que el manejo de excepciones en Python es muy problemático, si tenemos que usar grep o analizadores fuente para tratar con algo tan básico (que por ejemplo en Java existía desde el día Uno. A veces la verbosidad es algo bueno. Java es detallado, pero al menos no hay sorpresas desagradables. – GabiMe
@GabiMe, No es que esta capacidad (o el tipado estático en general) sea una bala de plata para evitar todos los errores. Java es _full_ de sorpresas desagradables. Es por eso que el eclipse se bloquea regularmente. –
@gnibber, claro, pero seguro que ayuda a prevenir muchos errores. – GabiMe
Nadie explicó hasta ahora, por qué no puede tener una lista completa y 100% correcta de excepciones, así que pensé que vale la pena comentar. Una de las razones es una función de primera clase. Digamos que usted tiene una función como esta:
def apl(f,arg):
return f(arg)
ahora apl
puede plantear cualquier excepción que plantea f
. Si bien no hay muchas funciones como esa en la biblioteca principal, todo lo que utiliza la comprensión de listas con filtros personalizados, mapas, reducir, etc. se ve afectado.
La documentación y los analizadores de origen son las únicas fuentes de información "serias" aquí. Solo tenga en cuenta lo que no pueden hacer.
Hay dos formas en que encuentro informativo. El primero, ejecuta las instrucciones en iPython, que mostrará el tipo de excepción.
n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'
En la segunda forma, nos conformamos con atrapar demasiado y mejorarlo. Incluya una expresión try en su código y capture excepto Exception como err. Imprima datos suficientes para saber qué excepción se produjo. A medida que se lanzan excepciones, mejore su código agregando una cláusula except más precisa. Cuando sienta que ha guardado en caché todas las excepciones relevantes, elimine el todo incluido. Algo bueno que hacer de todos modos porque absorbe los errores de programación.
- 1. Averiguar qué excepciones un método puede lanzar en C#
- 2. ¿Qué arrojar al lanzar excepciones de C++?
- 3. ¿Cómo lidiar con no saber qué excepciones se pueden plantear mediante un método de biblioteca en Ruby?
- 4. Terminología: ¿se pueden "lanzar" eventos?
- 5. ¿Suprimir-atrapar o lanzar excepciones que nunca pueden ocurrir?
- 6. Lanzar excepciones y notificar al usuario
- 7. ¿Cómo puedo saber qué eventos se disparan desde GXT?
- 8. Definición de excepciones que se pueden generar desde un kit de herramientas API
- 9. ¿Cómo puedo lanzar ipython desde el shell, ejecutando 'python ...'?
- 10. Evitar que Visual Studio se rompa al lanzar excepciones
- 11. Android Facebook.autorizar no llame al método completo
- 12. ¿Por qué volver a lanzar excepciones?
- 13. Declarar y lanzar contra lanzar sin excepciones
- 14. Llame al HttpHandler asp.net predeterminado desde un controlador personalizado
- 15. ¿Es normal que se llame varias veces al método "activity.onCreate()"
- 16. Cómo lanzar 404 excepciones en Zend Framework
- 17. ¿Cómo puedo saber qué datos se proporcionan en un paquete?
- 18. Evitar que se llame a un método antes que otro
- 19. ¿Desea lanzar excepciones en un autocargador SPL?
- 20. unidad prueba un método que llame al servicio wcf
- 21. operador sobrecargado no lanzar excepciones
- 22. Enumerable.Cast <T> método de extensión falla al lanzar desde int a long, ¿por qué?
- 23. Lanzar excepciones personalizadas en Java
- 24. ¿Qué excepciones podría lanzar string = string además de System.OutOfMemoryException?
- 25. ¿Qué causa que se llame al "método independiente __init __() con la instancia como primer argumento" de este código Python?
- 26. CodeDom - Llame a un método genérico
- 27. ¿Cómo puedo usar OCMock para verificar que nunca se llame a un método?
- 28. ¿Se pueden lanzar objetos con constructores de copia privada?
- 29. C# que define explícitamente qué excepciones se lanzan
- 30. ¿Hay un método UIViewController que se llame automáticamente cuando la aplicación se mueve al fondo?
Tenga en cuenta que en Python <2.6, también puede 'subir' cadenas, no solo las subclases 'BaseException'. Entonces, si llama al código de la biblioteca que está fuera de su control, incluso 'excepto Excepción' no es suficiente, ya que no detectará las excepciones de cadena. Como otros han señalado, estás ladrando el árbol equivocado aquí. –
No lo sabía. Pensé excepto Excepción: ... atrapa casi todo. – GabiMe
'except Exception' funciona bien para capturar excepciones de cadenas en Python 2.6 y versiones posteriores. –