- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议46:使用 traceback 获取栈信息
当程序产生异常的时候,最需要面对异常的其实是开发人员,他们需要更多的异常提示的信息,以便调试程序中潜在的错误和问题。先来看一个简单的例子:
gList = ['a','b','c','d','e','f','g'] def f(): gList[5] return g() def g(): return h() def h(): del gList[2] return i() def i(): gList.append('i') print gList[7] if __name__ == '__main__': try: f() except IndexError as ex: print "Sorry,Exception occured,you accessed an element out of range" print ex
上述程序运行输出如下:
Sorry,Exception occured,you accessed an element out of range list index out of range
信息提示有异常产生,对于用户这点还算是较为友好的,那么对于开发人员,他如何快速地知道错误发生在哪里呢?逐行检查代码吗?对于简单的程序,这也不失为一个办法,但在较为复杂的应用程序中这个方法就显得有点低效了。面对异常开发人员最希望看到的往往是异常发生时候的现场信息,traceback模块可以满足这个需求,它会输出完整的栈信息。将上述代码异常部分修改如下:
except IndexError as ex: print "Sorry,Exception occured,you accessed an element out of range" print ex traceback.print_exc()
程序运行会输出异常发生时候完整的栈信息,包括调用顺序、异常发生的语句、错误类型等。
Sorry,Exception occured,you accessed an element out of rangelist index out of range Traceback (most recent call last): File "trace.py", line 20, in <module> f() File "trace.py", line 5, in f return g() File "trace.py", line 8, in g return h() File "trace.py", line 12, in h return i() File "trace.py", line 16, in i print gList[7] IndexError: list index out of range
traceback.print_exc()方法打印出的信息包括3部分:错误类型(IndexError)、错误对应的值(list index out of range)以及具体的trace信息,包括文件名、具体的行号、函数名以及对应的源代码。Traceback模块提供了一系列方法来获取和显示异常发生时候的trace相关信息,下面列举几个常用的方法:
1)traceback.print_exception(type, value, traceback[, limit[, file]]),根据limit的设置打印栈信息,file为None的情况下定位到sys.stderr,否则则写入文件;其中type、value、traceback这3个参数对应的值可以从sys.exc_info()中获取。
2)raceback.print_exc([limit[, file]]),为print_exception()函数的缩写,不需要传入type、value、traceback这3个参数。
3)traceback.format_exc([limit]),与print_exc()类似,区别在于返回形式为字符串。
4)traceback.extract_stack([file,[, limit]]),从当前栈帧中提取trace信息。
读者可以参看Python文档获取更多关于traceback所提供的抽取、格式化或者打印程序运行时候的栈跟踪信息的方法。本质上模块trackback获取异常相关的数据都是通过sys.exc_info()函数得到的。当有异常发生的时候,该函数以元组的形式返回(type, value, traceback),其中type为异常的类型,value为异常本身,traceback为异常发生时候的调用和堆栈信息,它是一个traceback对象,对象中包含出错的行数、位置等数据。上面的例子中也可以通过如下方式输出异常发生时候的详细信息:
tb_type, tb_val, exc_tb = sys.exc_info() for filename, linenum, funcname, source in traceback.extract_tb(exc_tb): print "%-23s:%s '%s' in %s()" % (filename, linenum, source, funcname)
实际上除了traceback模块本身,inspect模块也提供了获取traceback对象的接口,inspect.trace([context])可以返回当前帧对象以及异常发生时进行捕获的帧对象之间的所有栈帧记录列表,因此第一个记录代表当前调用对象,最后一个代表异常发生时候的对象。其中每一个列表元素都是一个由6个元素组成的元组:(frame对象,文件名,当前行号,函数名,源代码列表,当前行在源代码列表中的位置)。本节开头的例子在异常部分使用inspect.trace()来获取异常发生时候的堆栈信息,其部分输出结果如下:
[(<frame object at 0x022CB480>, 'testinspect.py', 23, '<module>', ['\t f()\n'], 0), ... ...]
此外如果想进一步追踪函数调用的情况,还可以通过inspect模块的inspect.stack()函数查看函数层级调用的栈相信信息。因此,当异常发生的时候,合理使用上述模块中的方法可以快速地定位程序中的问题所在。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论