代码之家  ›  专栏  ›  技术社区  ›  Albert

Python:检查异常引发的位置

  •  2
  • Albert  · 技术社区  · 14 年前

    获取此代码:

    def A():
       try:
          B()
       except Exception:
          pass
    
    def B():
       C()
    
    def C():
       print exception_handling_pointer()
    
    A()
    

    功能 exception_handling_pointer 应该返回一个指向函数的指针,在该函数中,将首先检查是否处理此特定异常。也就是说,在这种情况下,我希望输出如下:

    <function A ...>
    

    如何实现该功能 异常处理指针 ?

    2 回复  |  直到 14 年前
        1
  •  2
  •   aaronasterling    14 年前

    这是一件非常愚蠢的事情,大多数人会说这是做不到的(THC4k为一般的cace提供了令人信服的证据),但这听起来确实很有趣,在许多实际的用例中应该是完全可行的。

    步骤1 . 你需要退后一步。拿第一个 sys._getframe inspect.currentframe (不要告诉任何人,第二个似乎是第一个的别名)。然后你可以用 f.f_back

    步骤2 . 每个人都有一个 f.f_lasti 指示。这是在帧中执行的最后一条指令。你必须保存它。现在,通过字节码返回单词- f.f_code.co_code -找一个 SETUP_EXCEPT 带参数的操作码跳转到 之后 福拉斯蒂。跳转点是异常处理。

    步骤3 . 这就是它变得更模糊的地方。关键是实际的比较操作将是 COMPARE_OP 以10作为论据。在我见过的所有情况下 POP_JUMP_IF_FALSE . 这将跳到下一个 except 条款或 finally 条款。它的前面是将异常加载到堆栈中的代码。如果只有一个,那么它将是一条直线 LOAD_GLOBAL 或者 加载全局 LOAD_FAST (取决于有异常的模块是全局的还是本地的)后跟 LOAD_ATTR . 如果匹配了多个异常,则将有一系列加载操作,然后 BUILD_TUPLE (习语)或 BUILD_LIST (一些其他奇怪的或非惯用的情况)。

    关键是你可以通过 LOAD_X 说明并将名称与匹配的异常进行比较。注意你是 仅比较名称 . 如果他们重新分配了名字,你就是索尔。

    步骤4 . 假设你找到了一个匹配的。现在需要函数对象。我能想到的最好的方法如下(我保留更新的权利): f.f_code 会有一个 co_filename 属性。你可以绕过去 sys.modules 每个人都会 __name__ 属性。你可以比较这两者,记住你应该使用 __name__.endswith(co_filename) . 当得到匹配时,可以循环遍历模块函数并比较它们 f.func_code.co_firstlineno 带有框架的属性 f.f_lineno 属性。当你得到一个匹配,你有你的功能。您还应该循环模块中每个类的方法。处理可能发生在某个嵌套函数中,在这种情况下,我现在想不出一个明智的做法。(这将是另一种字节码破解,而且本身也会变得松散)

    步骤5 . 利润。

    这应该能让你大致了解怎么做。有各种各样的角落情况,你将无法做到这一点,但在任何正常的用例,你应该能够做到这一点。如果你写的代码依赖于你的能力,它 突破。这是一种“因为我能”的事情。

        2
  •  3
  •   Jochen Ritzel    14 年前

    如果不实际引发异常,则无法决定在何处处理异常。这里很容易看到:

    try: 
        raise input('Raise which?')
    except input('Catch which?') as e: 
        pass`
    

    任何做你想做的事情的函数都必须在这里预测用户输入。整个努力都是徒劳的,Python不支持它。

    不管怎样,我希望你这样问只是出于兴趣。。。