Python:检查异常引发的位置

时间:2010-11-28 17:49:26

标签: python exception inspect

拿这段代码:

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

def B():
   C()

def C():
   print exception_handling_pointer()

A()

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

<function A ...>

如何实现函数exception_handling_pointer

2 个答案:

答案 0 :(得分:3)

如果不实际引发异常,您无法确定处理异常的位置。这很容易看到:

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

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

无论如何,我希望你只是出于兴趣......

答案 1 :(得分:2)

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

第1步。你需要退一步。获得第一个sys._getframeinspect.currentframe(不要告诉任何人,第二个似乎是第一个别名)。然后,您可以使用f.f_back

进行迭代

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

第3步。这是它变得更模糊的地方。关键是实际的比较操作是COMPARE_OP,其参数为10。在我见过的所有情况下,都跟着POP_JUMP_IF_FALSE。这将跳转到下一个except子句或finally子句。在它之前将加载异常的代码加载到堆栈上。如果只有一个,那么它将是直的LOAD_GLOBALLOAD_GLOBALLOAD_FAST(取决于具有例外的模块是全局还是本地),后跟{{1} }。如果匹配了多个异常,则会有一系列加载操作,然后是LOAD_ATTR(惯用)或BUILD_TUPLE(其他一些奇怪或非惯用的情况)。

关键是您可以浏览BUILD_LIST指令并将名称与您匹配的例外进行比较。请注意,您仅比较名称。如果他们重新分配了这个名字,你就是SOL。

第4步。我们假设您找到了匹配项。现在您需要功能对象。我可以考虑这样做的最佳方式(我保留更新权):LOAD_X将具有f.f_code属性。您可以遍历co_filename,每个人都有sys.modules属性。你可以比较两者,记住你应该使用__name__。获得匹配后,您可以遍历模块函数并将其__name__.endswith(co_filename)属性与框架f.func_code.co_firstlineno属性进行比较。当你得到一个匹配,你有你的功能。您应该循环遍历模块中每个类的方法。有可能在某些嵌套函数中进行处理,在这种情况下,我目前无法想到一件明智的事情。 (这将是一个完整的其他字节码黑客,本身就会变得非常脆弱)

第5步。利润。

这应该可以让您了解如何进行此操作。有各种各样的角落情况,你无法做到,但在任何正常的使用情况下,你应该能够把它拉下来。如果您编写的代码依赖于能够执行此操作,那么打破。这就是“做因为我可以”的事情。