拿这段代码:
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
?
答案 0 :(得分:3)
如果不实际引发异常,您无法确定处理异常的位置。这很容易看到:
try:
raise input('Raise which?')
except input('Catch which?') as e:
pass`
执行您想要的任何功能都必须在此处预测用户输入。整个努力是徒劳的,Python不支持它。
无论如何,我希望你只是出于兴趣......
答案 1 :(得分:2)
这是一个非常愚蠢的事情,大多数人会说它无法完成(THC4k为一般的cace提供了令人信服的证据)但它确实听起来很有趣,应该在许多实际使用中完全可行 - 例。
第1步。你需要退一步。获得第一个sys._getframe
或inspect.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_GLOBAL
或LOAD_GLOBAL
或LOAD_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步。利润。
这应该可以让您了解如何进行此操作。有各种各样的角落情况,你无法做到,但在任何正常的使用情况下,你应该能够把它拉下来。如果您编写的代码依赖于能够执行此操作,那么将打破。这就是“做因为我可以”的事情。