如何在不知道类型的情况下捕获 python 中的异常并获取对该异常的引用?

发布于 2024-08-17 04:36:18 字数 1049 浏览 1 评论 0原文

我想知道如何捕获任何引发的对象(即不扩展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's no reference to the exception that was raised

我可以通过导入 Java 异常类型并显式捕获它来解决这个问题,但这使得编写通用异常处理包装器/装饰器变得困难/不可能。

有没有办法捕获任意异常并仍然在 except 块中获取对其的引用?

我应该指出,我希望我制作的异常处理装饰器能够用于 Python 项目,而不仅仅是 Jython 项目。我想避免导入 java.lang.Exception,因为这只会使其成为 Jython 专用。例如,我认为我可以做这样的事情(但我还没有尝试过),但如果可以的话我想避免它。

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

I'm wondering how I can catch any raised object (i.e. a type that does not extend Exception), and still get a reference to it.

I came across the desire to do this when using Jython. When calling a Java method, if that method raises an exception, it will not extend Python's Exception class, so a block like this will not catch it:

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

I can do this, but then I have no access to the exception object that was raised.

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

I can solve this by importing the Java exception type and catching it explicitly, but this makes it difficult/impossible to write generic exception handling wrappers/decorators.

Is there a way to catch some arbitrary exception and still get a reference to it in the except block?

I should note that I'm hoping for the exception handling decorator I am making to be usable with Python projects, not just with Jython projects. I'd like to avoid importing java.lang.Exception because that just makes it Jython-only. For example, I figure I can do something like this (but I haven't tried it), but I'd like to avoid it if I can.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月光色 2024-08-24 04:36:18

您可以使用 sys 模块引用异常。 sys.exc_info 是一个元组类型、实例和回溯。

import sys

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

You can reference exceptions using the sys module. sys.exc_info is a tuple of the type, the instance and the traceback.

import sys

try:
    # some call to a java lib that raises an exception here
except:
    instance = sys.exc_info()[1]
是你 2024-08-24 04:36:18

FWIW,我发现如果您将此导入添加到 Jython 脚本中:

from java.lang import Exception

并且仅使用传统的 Python 异常处理程序:

except Exception, e:

它将捕获 Python 异常和 Java 异常

FWIW, I have found that if you add this import to your Jython script:

from java.lang import Exception

and just use the conventional Python Exception handler:

except Exception, e:

it will catch both Python exceptions and Java exceptions

薄荷港 2024-08-24 04:36:18

仅供感兴趣的人...我花了一些时间测试东西,因为我想找出如何获得正确的堆栈跟踪,无论是 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() )

Just for anyone interested... I spent a bit of time testing stuff because I wanted to find out how to get a proper stack trace whether a Python Exception (BaseException in fact, which is the base class) or a java.lang.Throwable (java base class for Exception, Error, etc.) is thrown... this code illustrates how to catch all line number refs correctly.

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

After this one might think of writing a decorator to precede def run( self ) and similar methods so that you don't have to write out this catch-the-Throwable try-except block each time... specifically:

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() )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文