意外收获:get_caller

阅读更多
阅读 PLY 的 lex.py 的时候,看到这么一段代码 (line:449):
try:
raise RuntimeError
except RuntimeError:
e,b,t = sys.exc_info()
f = t.tb_frame
f = f.f_back # Walk out to our calling function
ldict = f.f_globals # Grab its globals dictionary
哈哈,这种用法还真是前所未见(也许是见识还不够吧)!自己抛出异常自己捕捉,然后就可以访问到 frame stack 了!那还不无法无天了啊,呵呵。

你可以在这个 frame stack 中前后移动,这样你可以获得调用者的信息:比如 f_globals、f_locals、f_builtins、f_code 等,你还可以获得调用者的调用者的信息,你还可以获得 ... 。

而且获得了调用者的字节码( f_code )之后,你还可以直接把它再执行一遍!
import sys

count = 0

def get_caller():
global count
try:
raise RuntimeError
except RuntimeError:
e,b,t = sys.exc_info()
f = t.tb_frame
f = f.f_back
count += 1
print count
eval(f.f_code, f.f_globals, f.f_locals)

def caller():
get_caller()

if __name__=='__main__':
caller()
大家还有什么变态的想法,尽管留言哈 ^_^ .


另外,查看 sys.exc_info 的文档时候,看到有一个警告,大意是说 sys.exc_info() 返回的那个 traceback 对象( 返回的 tuple 中第三个),最好不要赋值给当前捕捉到异常的这个函数的局部变量,如果你不需要用到 traceback 对象的话可以这么干:
exctype, value = sys.exc_info()[:2]
如果你确实需要使用这个对象,那你最好用完后 delete 掉这个变量,或者在另外开一个函数来调用 sys.exc_info()。
理由是将 traceback 对象赋值给当前函数的局部变量会产生引用循环,而这个东西是引用计数垃圾回收方式的软肋,python2.2 以前的版本它直接就会导致内存泄露了,虽然随后版本的gc能搞定引用循环问题,不过考虑到效率,最好还是不要创建引用循环了。

你可能感兴趣的:(F#)