tipos - que es un error de sintaxis en python
¿Cómo capturar una excepción en python y obtener una referencia a la excepción, SIN saber el tipo? (3)
Me pregunto cómo puedo capturar cualquier objeto levantado (es decir, un tipo que no extienda la Exception
) y aún así obtener una referencia a él.
Encontré el deseo de hacer esto cuando uso Jython. Al llamar a un método Java, si ese método genera una excepción, no extenderá la clase de Exception
de Python, por lo que un bloque como este no lo detectará:
try:
# some call to a java lib that raises an exception here
except Exception, e:
# will never be entered
Puedo hacer esto, pero luego no tengo acceso al objeto de excepción que se generó.
try:
# some call to a java lib that raises an exception here
except:
# will enter here, but there''s no reference to the exception that was raised
Puedo resolver esto importando el tipo de excepción de Java y capturándolo explícitamente, pero esto hace que sea difícil / imposible escribir envoltorios / decoradores genéricos para el manejo de excepciones.
¿Hay alguna forma de detectar alguna excepción arbitraria y aún así obtener una referencia a ella en el bloque de except
?
Debo tener en cuenta que espero que el decorador de manejo de excepciones que estoy haciendo sea utilizable para proyectos Python, no solo para proyectos Jython. Me gustaría evitar importar java.lang.Exception
porque solo lo hace Jython-only. Por ejemplo, me imagino que puedo hacer algo como esto (pero no lo he intentado), pero me gustaría evitarlo si puedo.
try:
# some function that may be running jython and may raise a java exception
except (Exception, java.lang.Exception), e:
# I imagine this would work, but it makes the code jython-only
FWIW, he encontrado que si agrega esta importación a su script Jython:
from java.lang import Exception
y simplemente use el controlador de excepciones de Python convencional:
except Exception, e:
capturará las excepciones de Python y las excepciones de Java
Puede hacer referencia a las excepciones utilizando el módulo sys
. sys.exc_info
es una tupla del tipo, la instancia y el rastreo.
import sys
try:
# some call to a java lib that raises an exception here
except:
instance = sys.exc_info()[1]
Solo para cualquier persona interesada ... Pasé un poco de tiempo probando cosas porque quería averiguar cómo obtener un seguimiento de pila adecuado si una Excepción de Python (de hecho, la BaseException, que es la clase base) o una java.lang.Throwable (se lanza la clase base de Java para Exception, Error, etc.) ... este código ilustra cómo capturar correctamente todas las referencias de números de línea.
import sys
import traceback
import java
print "hello world"
def custom_hook( type, exc, tb ):
if isinstance( sys.exc_info()[ 1 ], java.lang.Throwable ):
sys.stderr.write( "AS JAVA:/n" )
sys.exc_info()[ 1 ].printStackTrace() # java part
else:
sys.stderr.write( "NO JAVA TRACE:/n" )
sys.stderr.write( "AS PYTHON:/n" )
traceback.print_exc()
# useful for custom exception handling!
sys.excepthook = custom_hook
def handle_exc():
# generate either a java.lang.Throwable (uncomment the next line and comment out "a = 16 / 0"
# java.lang.String( None )
# OR... a python-style BaseException:
a = 16 / 0
class Task( java.lang.Runnable ):
def run( self ):
# NB the problem with all this stuff is that the Java stack trace shows
# a java.lang.Throwable occurring at the last line of this code block...
# print "lots of stuff first"
# print "lots 2"
# handle_exc()
# print "lots 3"
# print "lots of stuff after"
try:
print "lots of stuff first"
print "lots 2"
handle_exc()
print "lots 3"
print "lots of stuff after"
# NB do not catch both (Python) BaseException and java.lang.Throwable...
# except ( BaseException, java.lang.Throwable ), e:
# the above means that the line no. in handle_exc is not shown when a BaseException
# is thrown...
except java.lang.Throwable, t:
tb = sys.exc_info()[ 2 ]
sys.stderr.write( "java.lang.Throwable thrown at: %s/n" % tb.tb_lineno )
raise t
java.awt.EventQueue.invokeAndWait( Task() )
Después de esto, se podría pensar en escribir un decorador para preceder a los métodos def run (self) y similares para que no tenga que escribir este bloque try-except catch-the-Throwable cada vez ... específicamente:
def throw_trap( function ):
def wrapper(*args, **kvargs):
try:
return function( *args, **kvargs )
except java.lang.Throwable, t:
tb = sys.exc_info()[ 2 ]
while( tb ):
sys.stderr.write( "thrown at: %s/n" % tb.tb_lineno )
tb = tb.tb_next
raise t
return wrapper
def handle_exc():
java.lang.String( None )
# a = 16 / 0
class Task( java.lang.Runnable ):
@throw_trap
def run( self ):
print "lots of stuff first"
print "lots 2"
handle_exc()
print "lots 3"
print "lots of stuff after"
java.awt.EventQueue.invokeAndWait( Task() )