Python的异常处理与调试方法

exception handling and debugging method

Posted by baiyf on June 27, 2018

Python的异常处理与调试方法

异常即非正常状态,Python使用异常对象来表示异常,如果程序在编译或运行过程中发生错误,程序的执行过程就会发生变化,抛出异常对象。

程序进入异常处理,如果异常对象没有被处理或者捕捉,程序就会执行回溯(Traceback)来终止程序。

Python标准异常

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

Exception类:通用异常基类下列异常均继承于Exception类,Python解释器会自动将通用异常类型名称放在内建命名空间中

处理异常

try…except…finally

示例如下:

try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

输出结果是:

try...
ValueError: invalid literal for int() with base 10: 'a'
finally...
END

可以看出来,这段代码的运行逻辑是先运行try内的代码块,如果捕捉到错误,则把错误给相应的except语句, as关键字用来获取异常信息,将异常信息传递给except语句;

如果整个try代码块都没有异常,就执行else block;最后无论是否有异常都执行finally语句块

需要注意的是,使用except不但捕获该类型的错误,还将其子类错误全部捕获,所以子类except是捕获不到异常的,常见错误类型和继承关系

捕获多种异常

方法一:指定一个通用异常,可以捕获多个子类异常

try:
    # try_block
except Exception:
    # except_block

方法二:在一个except子句后将多个异常作为元组元素列出

try:
    # try_block
except (IOError, ValueError):
    # except_block

方法三:except子句后不带任何异常名称,捕获所有异常

try:
    # try_block
except:
    # except_block

traceback追踪异常

可以使用traceback模块来追踪异常信息,这个模块可以帮助查看异常的详细信息,示例如下

import traceback
try:
    openFile = open('notExistsFile.txt','r')
    fileContent = openFile.readlines()
except IOError as info:
    print('File not Exists')
    print(info)
    traceback.print_exc()
    print('continue')
except:
    print('process exception')
else:
    print('Reading the file')

调试

除了用print()以外,Python还有以下几种方法可以在调试程序时灵活使用,断言(assert)、logging、pdb

断言

凡是可以用print查看的地方,都可以用assert,下面是一个例子

def testAssert(x):
    assert x < 1,'Invalid value'
testAssert(1)
print 'Valid value'

若assert statement为True,则向下执行;若assert statement为False,则终端程序并调用默认的异常处理器,同时输出提示信息AssertionError

当完成调试时,可以以-O参数来启动Python解释器,关闭assert,所有的assert语句就相当于不存在啦

logging

把print()替换为logging也是一种方法,与assert相比,logging不会也不能抛出错误,而且可以输出到文件

import logging
logging.basicConfig(level=logging.INFO) # 用于灵活的配置logging信息的级别

s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)

logging的好处就在于,我们可以灵活的指定记录信息的级别,有debug,info, warning,error几个级别。这样我们就可以统一控制输出哪个级别的信息,非常灵活

pdb

可以用-m pdb参数启动pdb调试器

命令n,执行下一行代码

命令1,查看代码

命令p 变量名,查看变量的值

命令q, 退出程序

pdb.set_trace()

给python程序设置一个断点,程序运行到pdb.set_trace()暂停并自动进入pdb调试环境:

# err.py
import pdb

s = '0'
n = int(s)
pdb.set_trace() # 运行到这里会自动暂停
print(10 / n)

命令c, 继续运行