阅读 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能搞定引用循环问题,不过考虑到效率,最好还是不要创建引用循环了。
0 评论:
发表评论