Подтвердить что ты не робот

Как поймать исключение в python и получить ссылку на исключение, БЕЗ зная тип?

Мне интересно, как я могу поймать любой поднятый объект (т.е. тип, который не расширяет Exception), и все равно получить ссылку на него.

Я столкнулся с желанием сделать это при использовании Jython. При вызове метода Java, если этот метод вызывает исключение, он не будет распространять класс Python Exception, поэтому блок, подобный этому, не сможет его уловить:

try:
    # some call to a java lib that raises an exception here
except Exception, e:
    # will never be entered

Я могу сделать это, но тогда у меня нет доступа к объекту исключения, который был поднят.

try:
    # some call to a java lib that raises an exception here
except:
    # will enter here, but there no reference to the exception that was raised

Я могу решить эту проблему, импортировав тип исключения Java и поймав его явно, но это затрудняет/невозможно писать общие обертки/обработчики обработки исключений.

Есть ли способ уловить какое-либо произвольное исключение и все еще получить ссылку на него в блоке except?

Я должен отметить, что я надеюсь на обработчик обработки исключений, который я делаю для использования с проектами Python, а не только с проектами Jython. Я бы хотел избежать импорта java.lang.Exception, потому что это просто делает Jython-only. Например, я полагаю, что могу сделать что-то вроде этого (но я его не пробовал), но я бы хотел избежать этого, если смогу.

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
4b9b3361

Ответ 1

Вы можете ссылаться на исключения, используя модуль sys. sys.exc_info является кортежем типа, экземпляра и трассировки.

import sys

try:
    # some call to a java lib that raises an exception here
except:
    instance = sys.exc_info()[1]

Ответ 2

FWIW, я обнаружил, что если вы добавите этот импорт в свой Jython script:

from java.lang import Exception

и просто используйте обычный обработчик исключений Python:

except Exception, e:

он будет улавливать как исключения Python, так и исключения Java

Ответ 3

Просто для всех, кого это интересует... Я потратил немного времени на тестирование, потому что хотел узнать, как получить правильную трассировку стека, будь то исключение Python (BaseException на самом деле, что является базовым классом) или java. lang.Throwable(базовый класс java для исключения, ошибки и т.д.)... этот код иллюстрирует, как правильно правильно исправить все номера строк.

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

После этого можно подумать о написании декоратора, который должен предшествовать def run (self) и аналогичным методам, так что вам не нужно каждый раз выписывать этот catch-the-Throwable блок try-except... в частности:

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