2

拿这个代码:

def A():
   try:
      B()
   except Exception:
      pass

def B():
   C()

def C():
   print exception_handling_pointer()

A()

该函数exception_handling_pointer应该返回一个指向函数的指针,该函数将首先检查此特定异常是否被处理。即,在这种情况下,我希望输出是 sth。像:

<function A ...>

如何实现该功能exception_handling_pointer

4

2 回答 2

3

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

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

任何执行您想要的功能都必须在此处预测用户输入。整个努力都是徒劳的,Python 不支持它。

无论如何,我希望您只是出于兴趣而问...

于 2010-11-28T18:03:46.860 回答
2

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

步骤 1。您需要退后一步。sys._getframe用or获取第一个inspect.currentframe(不要告诉任何人,第二个似乎与第一个有别名)。然后你可以遍历它们f.f_back

步骤 2。每个人都会有一个f.f_lasti指示。这是帧中执行的最后一条指令。你必须保存它。现在遍历字节码 - f.f_code.co_code- 并查找SETUP_EXCEPT带有跳转到f.f_lasti`之后的参数的操作码。跳转点是异常处理。

步骤 3。这是它变得更加模糊的地方。关键是实际的比较操作将以COMPARE_OP10 作为参数。在我见过的所有情况下,它后面都跟着一个POP_JUMP_IF_FALSE. 这将跳转到下一个except子句或该finally子句。它前面是加载异常到堆栈的代码。如果只有一个,那么它将是直接LOAD_GLOBAL的或 aLOAD_GLOBALLOAD_FAST(取决于具有异常的模块是全局的还是本地的)后跟 a LOAD_ATTR。如果有多个异常被匹配,那么将有一系列加载操作,然后是BUILD_TUPLE(惯用的)或BUILD_LIST(一些其他奇怪或非惯用的情况)。

关键是您可以浏览LOAD_X说明并将名称与您匹配的异常进行比较。请注意,您只比较 name。如果他们重新分配了名称,那么您就是 SOL。

步骤 4。假设您找到了匹配项。现在你需要函数对象。我能想到的最好方法如下(我保留更新的权利):f.f_code将有一个co_filename属性。你可以循环遍历sys.modules,每个都有__name__属性。您可以比较两者,记住您应该使用__name__.endswith(co_filename). 当你得到匹配时,你可以遍历模块函数并将它们的f.func_code.co_firstlineno属性与框架进行比较f.f_lineno属性。当你得到匹配时,你就有了你的功能。您还应该遍历模块中每个类的方法。处理可能发生在某些嵌套函数中,在这种情况下,我目前想不出明智的做法。(这将是一个完全不同的字节码黑客,本身就是脆弱的)

步骤 5。利润。

这应该让您大致了解如何执行此操作。在各种极端情况下您将无法做到这一点,但在任何正常的用例中,您都应该能够做到这一点。如果您编写的代码依赖于能够做到这一点,那么它中断。这是一种“因为我能做到”之类的事情。

于 2010-11-28T21:39:53.067 回答