1 异常和错误
1.1 错误和异常
从软件方面来说,错误是语法或者逻辑上的,语法错误指示软件的结构上有错误,导致不能被解释器解释。当程序的语法正确后,剩下的就是逻辑错误了,逻辑错误可能是由于不完整或者不合法的输入所致。当Python检测到一个错误时,解释器就会指出当前流无法继续执行下去,这就出现了异常。
对异常的描述是:它是因为程序出现了错误而在正常控制流以外采取的行为,这个行为又分为两个阶段:首先是引起异常发生的错误,然后是检测(和采取可能的措施)阶段。
第一个阶段是发生在一个异常条件后发生的,只要检测到错误并且意识到异常条件,解释器就会触发一个异常。解释器通知当前控制流有错误发生。异常就是错误发生的信号,当前流被打断,用来处理这个错误并采取相应的操作。这就是第二阶段。
对异常的处理发生在第二阶段,异常引发后,可以调用不同的操作,可以忽略错误,或是减轻问题的影响后设法继续执行,所有的这些操作都是代表一种继续,或是控制的分支。关键是程序员在错误发生时可以指示程序如何执行。
1.2 Python中的异常
NameError:尝试访问一个未声明的变量
ZeroDivisionError:除数为0
SyntaxError:Python解释器语法错误
IndexError:请求的索引超出序列范围
KeyError:请求一个不存在的字典关键字
IOError:输入/输出错误
AttributeError:尝试访问未知的对象属性
1.3 检测和处理异常
异常可以通过try语句来检测,任何在try语句块中的代码都会被检测,检测有无异常发生。
try语句有两种主要的形式:try-except和try-finally语句。这两个语句是互斥的,只能使用其中的一个。一个try语句可以对应一个或多个except语句,但只能对应一个finally语句,或者是一个try-except-finally复合语句。
1.4 try-except语句
try-except语句(以及更复杂的形式)定义了进行异常监控的一段代码,并且提供了异常处理的机制。
常见的语法格式如下:
1 try:2 try_suite #监控这里的异常
3 exceptException[, reason]:4 except_suite #异常处理的代码
1 举例:2 >>> try:3 ... f = open('bla', 'r')4 ... exceptIOError, e:5 ... print 'could not open file', e6 ...7 could not open file [Errno 2] No such file or directory: 'bla'
程序运行时,解释器尝试执行try里面的语句块,如果代码块执行后没有发生错误,执行流会忽略except语句继续执行,当except语句所指定的异常发生后,保存下错误的原因,控制流立即跳转到对应的处理器(try子句的剩余语句将被忽略)。
1.5 带有多个except的try语句
可以把多个except语句连接在一起,处理一个try块中可能发生的多种异常。如下:
1 try
2 try_suite #监控这里的异常
3 exceptException1 [, reason]:4 suite_for_exception_Exception15 exceptException2 [, reason]:6 suite_for_exception_Exception2
首先执行try子句,如果没有错误,忽略所有的except从句继续执行,如果发生异常,解释器将在这一串处理器(except子句)中查找匹配的异常,如果找到对应的处理器,执行流将跳转到这里。
1.5 处理多个异常的except语句
可以在一个except子句里处理多个异常,except语句在处理多个异常时要求异常被放在一个元组里:
1 except(Exception1, Exception2) [, reason]:2 suite_for_Exception1_and_Exception2
事实上except语句可以处理任意多个异常,前提只是他们放在一个元组里,如下:
1 except(Exc1,[, Exc2 [, … ExcN]]) [, reason]:2 suite_for_exceptions_Excl_to_ExcN
1.6 捕获所有异常
异常是遵循继承结构的,Exception是在最顶层。
1 try:2 ;3 exceptException. e:4 #error occurred, etc.
Python2.5,异常被迁移到了新式类上,启用了一个新的"所有的异常之母",这个类叫做BaseException,KeyboardInterrupt和SystemExit和Exception同级了。如果需要捕获所有的异常,格式如下:
1 try:2 ;3 exceptBaseException, e:4 #error occurred, etc.
1.8 "异常参数"
异常也可以有参数,异常引发后会被传递给异常处理器。当异常被引发后参数是作为附加帮助信息传递给异常处理器的。标准内建异常提供至少一个参数,指示异常原因的一个字符串。添加异常参数的except扩展语法如下:
1 except(Exception1, Exception2, …, ExceptionN), [, reason):2 suite_for_Exception1_to_ExceptionN_with_Argument
异常参数自身组成一个元组,并存储为类实例(异常类的实例)的属性。
1 #!/usr/bin/env python
2
3 defsafe_float(obj):4 'safa version of float()'
5 try:6 retval =float(obj)7 except(ValueError, TypeError), diag:8 retval =str(diag)9 returnretval10
11 defmain():12 'handle all the data processing'
13 log = open('cardlog.txt', 'w')14 try:15 ccfile = open('carddata.txt', 'r')16 exceptIOError, e:17 log.write('no txns this month\n')18 log.close()19 return
20 txns =ccfile.readlines()21 ccfile.close()22 total = 0.00
23 log.write('account log:\n')24
25 for eachTxn intxns:26 result =safe_float(eachTxn)27 ifisinstance(result, float):28 total +=result29 log.write('data... processed\n')30 else:31 log.write('ignord: %s' %result)32 print '$%.2f (new balance)' %(total)33 log.close()34
35 if __name__ == '__main__':36 main()
1.9 else子句
在try范围内没有异常被检测到时,执行else子句。在else范围中的任何代码执行前,在try范围中的所有代码必须完全成功。
1 try:2 ;3 exceptException. e:4 #error occurred, etc.
5 else:6 ;
1.11 finally子句
finally子句是无论异常是否发生,是否捕捉都会执行的一段代码。语法示例如下:
1 try:2 ;3 exceptException. e:4 #error occurred, etc.
5 else:6 ;
1.12 try-except-else-finally语句
综合所有不同的可以处理异常的语法样式如下:
1 try:2 try_suite3 exceptException1:4 suite_for_Exception15 except(Exception2, Exception3, Exception4):6 suite_for_Exception2_3_and_47 exceptException5, Argument5:8 suit_for_Exception5_plus_argument9 except(Exception6, Exception7), Argument67:10 suit_for_Exception6_and_Exception7_plus_argument11 except:12 suit_for_all_other_exceptions13 else:14 no_exceptions_detected_suits15 finally:16 always_execute_suite
2 上下文管理
2.1 with语句
with语句的目的在于从流程图中把try、except和finally关键字和资源分配释放相关的代码统统去掉。基本用法如下:
1 with context_expr [as var]:2 with_suite
with仅能工作支持上下文管理协议的对象,下面是一些支持该协议的对象:
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
用file来进行举例:
1 >>> with open('/etc/passwd', 'r') as f:2 ... for eachLine inf:3 ... #do stuff with eachLine of f...
无论在这一段代码的开始、中间或结束发生异常,会执行清除的代码,此时文件仍会被自动的关闭。
3 触发异常
raise语句用于触发异常,一般语法如下:
raise [SomeException [, args [, traceback]]]
第一个参数,SomeException,是触发异常的名字,如果有,必须是一个字符串、类或实例。
第二个符号为可选的args(比如参数、值),来传给异常。可以是一个单独的对象也可以是一个对象的元组。当异常发生时,异常的参数总是作为一个元组传入。
最后一个参数traceback是可选的,如果有的话,则是当异常触发时新生成的一个用于异常-正常化的跟踪记录对象。
4 断言
断言是一句必须等价于布尔真的判断,此外当异常发生也意味着表达式为假。如果断言成功不采取任何措施,否则触发AssertionError(断言错误)的异常,语法如下:
assert expression [, arguments]
举例:
1 >>> assert 1==1
2 >>> assert 1==2
3 Traceback (most recent call last):4 File "", line 1, in
5 AssertionError
AssertionError(断言错误)的异常也可以使用try-except捕捉。
附录:python内建异常
异常名称
描述
BaseException
所有异常的基类
SystemExit
Python解释器请求退出
KeyboardInterrupt
用户中断执行(通常是输入^C)
Exception
常规错误的基类
StopIteration
迭代器没有更多的值
GeneratorExit
生成器(generator)发生异常来通知退出
StandardError
所有的内建标准异常的基类
ArithmeticError
所有数值计算错误的基类
FloatingPointError
浮点计算错误
OverflowError
浮点运算超出最大限度
ZeroDivisionError
除(或取模)零(所有数据类型)
AssertionError
断言语句失败
EOFError
没有内建输入,到达EOF标记
EnvironmentError
操作系统错误的基类
IOError
输入/输出操作失败
OSError
操作系统错误
WindowsError
Windows系统调用失败
ImportError
导入模块/对象失败
LookupError
无效数据查询的基类
IndexError
序列中没有此索引
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)的警告
PendingDepressionWarning
关于特征将会被废弃的警告
RuntimeWarning
可以的运行时行为的警告
SyntaxWarning
可疑的语法的警告
UserWarning
用户代码生成的警告