【问题标题】:How do I check if current code is part of a try-except-block?如何检查当前代码是否是 try-except-block 的一部分?
【发布时间】:2019-09-07 19:13:23
【问题描述】:

我正在调试作为某种形式的插件框架的一部分编写的函数。该函数似乎没有做它应该做的事情,我怀疑,在堆栈的某个地方,有人正在捕获异常,或者引发(非常具体或非常通用)异常并测试发生了什么(但如果它是吞下,它仍然没有告诉我在哪里)。我可以进入调试器并检查每个堆栈级别的源代码。有没有更直接的方法来列出当前代码可能属于的任何 try-except 块——特别是任何此类块的 try-part?

当然,这仅用于调试目的。

【问题讨论】:

  • 这是一个有趣的问题!让我们看看...

标签: python debugging exception


【解决方案1】:

这是一个相当困难的问题:在内部,每个框架都维护a stack of blocks,但我认为没有任何 API 可以访问它(更不用说从 Python 中访问了)。因此,您必须遍历堆栈帧,反汇编代码以推断您的尝试块的跨度(请参阅SETUP_EXCEPTSETUP_FINALLY 操作码),并查看堆栈帧的“当前行”是否在该块内.

【讨论】:

    【解决方案2】:

    这是壮观可能我在这里遗漏了一些东西(我只是盯着catcher 函数的dis.dis() 输出),但至少这抓住了在Python 3.7 上捕获东西的简单案例:

    import sys
    import dis
    
    
    def are_we_being_caught():
        frame = sys._getframe(1)
        while frame:
            bytecode = dis.Bytecode(frame.f_code)
            except_stack = 0
            for instr in bytecode:
                if instr.opname == "SETUP_EXCEPT":  # Going into a try: except: block
                    except_stack += 1
                elif instr.opname == "POP_EXCEPT":  # Exiting a try: except: block
                    except_stack -= 1
                if instr.offset > frame.f_lasti:  # Past the current instruction, bail out
                    break
            if except_stack:  # If we `break`ed in the middle of a SETUP/POP pair
                print(frame, "may be catching exceptions now")
            frame = frame.f_back
    
    
    def catcher(fn):
        try:
            x = fn()
        except:
            x = None  # YOLO :D
        return x
    
    
    def f1():
        return 8
    
    
    def f2():
        are_we_being_caught()
        raise ValueError("foo")
    
    
    print(catcher(f1))
    print(catcher(f2))
    

    输出

    8
    <frame at 0x109d2d238, file 'so55729254.py', line 24, code catcher> may be catching exceptions now
    None
    

    【讨论】:

    • @gerrit 很好,是的。 :)
    • 这是一个漂亮的,尽管您可能还想处理 try/finally 块(IIRC 与 try/except 分开处理),因为 Python 允许,例如finally 块中的 return 语句,这将隐式抑制异常。
    • @AKX 我可以将您的食谱开发成 github 要点吗?或者也许你有兴趣自己这样做?或者我可以根据什么许可重复使用/开发您的食谱?
    • @gerrit 随意!我实际上在想它可能作为一个图书馆有用。虽然一般的 SO 许可证是 cc-by-sa 3.0,但我想 MIT 对代码很有用。 :)
    • 警告:如果你使用 Python IDLE 而不是命令行,那么它会报告/usr/lib/python3.7/idlelib/run.py 正在捕获异常。检查捕手== __file__是否是一个更好的主意...
    猜你喜欢
    • 2020-03-15
    • 1970-01-01
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 2021-06-22
    • 2021-08-27
    • 1970-01-01
    相关资源
    最近更新 更多