1、异常的由来
说到异常,通常首先要讲的是错误,在写程序的过程中,会出现各种各样的错误,可能是语法错误,也可能是逻辑错误,那么当程序再运行的过程中,如果是语法错误,那么必须修正之后才能进行运行,如果是逻辑错误,那么可能是不合法的输入,也有可能是不完整的输入,或者无法输出,运行到相关的范围就会出现了错误。
当python检测到一个错误之后,那么就会出现一个异常。
python程序的运行,先写出源代码文件以.py结尾的文件,然后由python解释器进行解释生成python字节码文件,通常以.pyc结尾,然后再将整个字节码文件到处理器上进行运行,当有一步出现错误的时候,就会产生一个异常。
异常:程序出现了错误而在正常控制流以外采取的行为。
通常异常会分为两个阶段:一个阶段是引起异常的错误,另外一个阶段是检测处理阶段。
2、异常的触发形式
异常可以是python解释器触发,也可以是手动触发。
当python解释器遇到错误的时候,那么就会抛出一个异常,如果这个异常没有被捕获,那么就会向上级程序抛出,一直到顶层程序,最后抛出异常,程序执行流程被中断,也就是当异常没有被捕获处理的时候,那么就会导致程序中断运行。
当手动触发的时候,可以使用raise语句来手动触发异常。
在捕获处理异常的时候,一般只能预见到部分异常,从而进行处理,在处理异常的时候,应该返回相关的错误信息,或者写入到相关的日志文件中,而不应该没有任何输出。
3、 python中常见的异常
python中常见的异常如下所示:
>>> foo (访问一个未定义的变量,产生NameErrot异常)
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> 3 +"a" (类型异常,不同的类型进行加操作,python是弱类型语言,只有在赋值之后才会有相关的类型)
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int'and 'str'
>>> for(语法异常)
File"<stdin>", line 1
for
^
SyntaxError: invalid syntax
>>> alist = [1];alist[3](索引异常)
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
IndexError: list index out of range
>>> (键盘异常)
KeyboardInterrupt
当在程序中出现异常之后,会导致程序的中断运行,如下所示:
[root@python tmp]# cat kel.py (模块文件内容如下,程序开始打印start,程序结束打印end)
#!/usr/bin/env python
print "start"
3 + "a"
print "end"
[root@python tmp]# python kel.py (打印了start,但是中间出现了异常,从而打破了正常的执行流程,异常发生后,后面的语句不会再执行,运行的程序中断)
start
Traceback (most recent call last):
File"kel.py", line 4, in <module>
3 +"a" (抛出了异常,异常后面的代码未执行)
TypeError: unsupported operand type(s) for +: 'int'and 'str'
4、检测和处理异常
在检测异常的时候,使用try关键字,在处理异常的时候,使用except语句,在其中,可以有多个except语句进行捕获不同类型的异常,当程序正常执行的时候,可以使用else语句来执行其他的流程,当出现异常或者程序都正常的时候,可以使用finally语句来进行一些程序的清理工作,例如将打开的文件进行关闭,
每个except可以处理一个异常,如下:
[root@python tmp]# cat commonutils.py (每个except捕获一个异常,并且返回异常的详细信息)
#!/usr/bin/env python
def safe_float(obj):
try:
retval= float(obj)
except ValueError,e:
retval= str(e)
except TypeError,e:
retval= str(e)
returnretval
if __name__ == "__main__":
printsafe_float("2b")
printsafe_float("2")
printsafe_float([1,2,3])
[root@python tmp]# python commonutils.py (当异常抛出的时候,异常被捕获并处理,从而程序会继续运行)
invalid literal for float(): 2b
2.0
float() argument must be a string or a number
一个except也可以处理多个异常,不过这些异常必须是元祖的形式存在,如下:
[root@python tmp]# cat commonutils.py (一个except处理多个异常,并返回错误信息)
#!/usr/bin/env python
def safe_float(obj):
try:
retval= float(obj)
except (TypeError,ValueError),e:
retval= str(e)
returnretval
if __name__ == "__main__":
printsafe_float("2b")
printsafe_float("2")
printsafe_float([1,2,3])
[root@python tmp]# python commonutils.py
invalid literal for float(): 2b
2.0
float() argument must be a string or a number(当异常抛出的时候,异常被捕获并处理,从而程序会继续运行)
使用else分支来表示正常执行的逻辑,如下所示:
[root@python tmp]# cat commonutils.py (当文件被正常打开之后,可以在else中做一些正常流程的事,如果触发了异常,那么else代码块中的语句不会被执行)
#!/usr/bin/env python
try:
f =open('/tmp/kel.txt')
except IOError,e:
printtype(e)
printstr(e)
else:
f.close()
print"file is closed"
[root@python tmp]# python commonutils.py
file is closed
finally子句表示无论异常是否发生,都是会执行,如下所示:
[root@python tmp]# cat commonutils.py
#!/usr/bin/env python
try:(监控异常)
f =open('/tmp/kel.txt')
except IOError,e(捕获异常):
printtype(e)
printstr(e)
else:(正常执行时候执行)
print"file is open"
finally:(无论是否触发异常都会执行)
print"always execute"
f.close()
[root@python tmp]# python commonutils.py
file is open
always execute
5、所有的异常都是类
所有的异常都是一个一个对象,如下所示:
[root@python tmp]# cat commonutils.py (查看异常的类型)
#!/usr/bin/env python
try:
f =open('/tmp/somefile.txt')
except IOError,e:
printtype(e)
printstr(e)
[root@python tmp]# python commonutils.py
<type 'exceptions.IOError'>
[Errno 2] No such file or directory:'/tmp/somefile.txt
在捕获异常的时候,这个异常的原因是可写可不写的,当写的时候,这个e是一个异常类对象的实例,从上面的type可以看出,这是一个IOError异常的实例,从而每次返回错误的信息时候,需要转换成字符串的方式,也就是str(e),在转换的时候,实际上是调用e.__str__方法。
异常对象的分类如下所示:
从而需要捕获所有的异常的时候,可以直接在except中写Exception捕捉所有的内置异常,但是建议不要这么做。
6、另外一种安全的打开文件的方式
在打开文件的时候,可能需要各种判断,但是可以使用更加简单的方法,那就是with语句:
[root@python tmp]# python commonutils.py
Traceback (most recent call last):
File"commonutils.py", line 5, in <module>
some
NameError: name 'some' is notdefined
[root@python tmp]# cat commonutils.py
#!/usr/bin/env python
with open('/tmp/kel.txt') as f: (会自动执行代码的清理工作,也就是会将打开的文件进行关闭,取代了finally的工作,也会自动的抛出异常,但是依旧需要自行判断文件是否存在)
foreachline in f:
some
printeachline
7、或许有用的例子
在进行组织一些基础类库的时候,例如在打开文件的时候,总要判断文件是否存在,那么可以写一个基础的函数,只要直接进行调用,然后返回文件句柄即可,不用每次都来进行判断,如下所示:
[root@python tmp]# cat openfile.py (直接调用打开的文件函数,返回文件句柄,在主程序中,无需进行判断文件是否存在,是否会发生io错误)
#!/usr/bin/env python
def openfile(filename,mode='r'):
try:
retval= open(filename,mode)
exceptIOError,e:
retval= None
returnretval
if __name__ == "__main__":
f =openfile('/tmp/kel.txt')
if f:
printlen(f.readlines())
f =openfile('tmp/somefile')
if f:
printlen(f.readlines())
[root@python tmp]# python openfile.py
4