Python 如何防止多次捕获异常

Python 如何防止多次捕获异常,python,oop,exception,exception-handling,Python,Oop,Exception,Exception Handling,当异常沿着堆栈上升到程序的顶层时,是否有方法防止多次捕获异常 下面是一个非常简化的代码示例,说明了这种现象: def try_except_block(smthg): try: smthg.run() except Exception as e: print("WRONG") raise e def re_call(): f2 = Foo(True) # will throw an exception try_except_block(f2

当异常沿着堆栈上升到程序的顶层时,是否有方法防止多次捕获异常

下面是一个非常简化的代码示例,说明了这种现象:

def try_except_block(smthg):
   try:
     smthg.run()
   except Exception as e:
     print("WRONG")
     raise e

def re_call():
   f2 = Foo(True) # will throw an exception
   try_except_block(f2)

class Foo:
  def __init__(self, t):
    self.throw = t
  def run(self):
    if self.throw:
      raise KeyError
    else:
      re_call()

if __name__ == '__main__':
  f = Foo(False) # won't throw an exception
  try_except_block(f)
输出:

WRONG
WRONG
Traceback (most recent call last):
  File "exception_loosing_args.py", line 26, in <module>
    try_except_block(f)
  File "exception_loosing_args.py", line 9, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 22, in run
    re_call()
  File "exception_loosing_args.py", line 13, in re_call
    try_except_block(f2)
  File "exception_loosing_args.py", line 9, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 20, in run
    raise KeyError
KeyError
WRONG
Traceback (most recent call last):
  File "exception_loosing_args.py", line 28, in <module>
    try_except_block(f)
  File "exception_loosing_args.py", line 11, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 24, in run
    re_call()
  File "exception_loosing_args.py", line 15, in re_call
    try_except_block(f2)
  File "exception_loosing_args.py", line 11, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 22, in run
    raise KeyError
KeyError
输出:

WRONG
WRONG
Traceback (most recent call last):
  File "exception_loosing_args.py", line 26, in <module>
    try_except_block(f)
  File "exception_loosing_args.py", line 9, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 22, in run
    re_call()
  File "exception_loosing_args.py", line 13, in re_call
    try_except_block(f2)
  File "exception_loosing_args.py", line 9, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 20, in run
    raise KeyError
KeyError
WRONG
Traceback (most recent call last):
  File "exception_loosing_args.py", line 28, in <module>
    try_except_block(f)
  File "exception_loosing_args.py", line 11, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 24, in run
    re_call()
  File "exception_loosing_args.py", line 15, in re_call
    try_except_block(f2)
  File "exception_loosing_args.py", line 11, in try_except_block
    raise e
  File "exception_loosing_args.py", line 6, in try_except_block
    smthg.run()
  File "exception_loosing_args.py", line 22, in run
    raise KeyError
KeyError
错误
回溯(最近一次呼叫最后一次):
文件“exception\u loosing\u args.py”,第28行,在
尝试除块(f)外的其他块
文件“exception\u loosing\u args.py”,第11行,在try\u except\u块中
提高e
文件“exception\u loosing\u args.py”,第6行,在try\u except\u块中
smthg.run()
文件“exception\u loosing\u args.py”,第24行,运行中
重新调用()
文件“exception\u loosing\u args.py”,第15行,在re\u调用中
除块(f2)外,尝试块
文件“exception\u loosing\u args.py”,第11行,在try\u except\u块中
提高e
文件“exception\u loosing\u args.py”,第6行,在try\u except\u块中
smthg.run()
文件“exception\u loosing\u args.py”,第22行,运行中
上升键错误
关键错误

我不完全理解为什么您的代码会这样做,但您可以做一件适合的事情,即将异常对象标记为已经看到的对象,而不是设置全局标志。像这样:

def try_except_block(smthg):
    try:
        smthg.run()
    except Exception as e:
        if not hasattr(e, "teb_already_seen"):
            setattr(e, "teb_already_seen", True)
            print("WRONG")
        raise e

这样,
try\u except\u block
所做的额外处理只会对每个异常对象发生一次,这可能是您想要的。

如果您不在
except
中重新引发异常,它将停止传播…从逻辑上讲,行为是正确的,您确实有两个嵌套的
try..except
块,两者都将捕获并重新引发异常,从而触发消息两次。也许使用一个不太复杂的递归逻辑将是这里最好的“修复”?谢谢你们。乔恩·克莱门茨:我需要在程序的顶层捕捉异常,以用于其他目的。我必须传播一个例外:这是一个进退两难的局面@我不能。这段代码涉及到递归访问图中的节点。这正是我想要防止产生副作用的原因。非常感谢。