错误和异常(2)
你们得救是本乎恩,也因着信。这并不是出于自己,乃是神所赐的;也不是出于行为,免得有人自夸。(EPHESIANS 2:8-9)
错误和异常(2)
处理多个异常
try...except...
是处理异常的基本方式。在此基础上,还可有扩展,能够处理多个异常。
处理多个异常,并不是因为同时报出多个异常。程序在运行中,只要遇到一个异常就会有反应,所以,每次捕获到的异常一定是一个。所谓处理多个异常的意思是可以容许捕获不同的异常,由不同的except
子句处理。
Python 2:
#!/usr/bin/env python# coding=utf-8while 1: print "this is a division program." c = raw_input("input 'c' continue, otherwise logout:") if c == 'c': a = raw_input("first number:") b = raw_input("second number:") try: print float(a)/float(b) print "*************************" except ZeroDivisionError: print "The second number can't be zero!" print "*************************" except ValueError: print "please input number." print "************************" else: break
Python 3:
#!/usr/bin/env python# coding=utf-8while 1: print("this is a division program.") c = input("input 'c' continue, otherwise logout:") if c == 'c': a = input("first number:") b = input("second number:") try: print(float(a)/float(b)) print("*************************") except ZeroDivisionError: print("The second number can't be zero!") print("*************************") except ValueError: print("please input number.") print("************************") else: break
将上节的一个程序进行修改,增加了一个except子句,目的是如果用户输入的不是数字时,捕获并处理这个异常。测试如下:
$ python 21701.py this is a division program.input 'c' continue, otherwise logout:cfirst number:3second number:"hello" #输入了一个不是数字的东西please input number. #对照上面的程序,捕获并处理了这个异常************************this is a division program.input 'c' continue, otherwise logout:cfirst number:4second number:0The second number can't be zero!*************************this is a division program.input 'c' continue, otherwise logout:4
如果有多个except
,try里面遇到一个异常,就转到相应的except
子句,其它的忽略。如果except
没有相应的异常,该异常也会抛出,不过这是程序就要中止了,因为异常“浮出”程序顶部。
除了用多个except
之外,还可以在一个except
后面放多个异常参数,比如上面的程序,可以将except
部分修改为:
except (ZeroDivisionError, ValueError): print "please input rightly." print "********************"
运行的结果就是:
$ python 21701.py this is a division program.input 'c' continue, otherwise logout:cfirst number:2second number:0 #捕获异常please input rightly.********************this is a division program.input 'c' continue, otherwise logout:cfirst number:3second number:a #异常please input rightly.********************this is a division program.input 'c' continue, otherwise logout:d$
需要注意的是,except
后面如果是多个参数,一定要用圆括号包裹起来。否则,后果自负。
在对异常的处理中,前面都是自己写一个提示语,发现自己写的不如内置的异常错误提示好。希望把它打印出来。但是程序还能不能中断,怎么办?
Python提供了一种方式,将上面代码修改如下:
Python 2:
while 1: print "this is a division program." c = raw_input("input 'c' continue, otherwise logout:") if c == 'c': a = raw_input("first number:") b = raw_input("second number:") try: print float(a)/float(b) print "*************************" except (ZeroDivisionError, ValueError), e: print e print "********************" else: break
Python 3:
while 1: print("this is a division program.") c = input("input 'c' continue, otherwise logout:") if c == 'c': a = input("first number:") b = input("second number:") try: print(float(a)/float(b)) print("*************************") except (ZeroDivisionError, ValueError) as e: print(e) print("********************") else: break
运行一下,看看提示信息。
$ python 21702.py this is a division program.input 'c' continue, otherwise logout:cfirst number:2second number:a #异常could not convert string to float: a********************this is a division program.input 'c' continue, otherwise logout:cfirst number:2second number:0 #异常float division by zero********************this is a division program.input 'c' continue, otherwise logout:d$
注意Python 3中的写法except (ZeroDivisionError, ValueError) as e:
在上面程序中,只处理了两个异常,还可能有更多的异常,如果要处理,怎么办?可以这样:execpt:
或者except Exception, e
、except Exception as e
,后面什么参数也不写就好了。
else子句
有了try...except...
,在一般情况下是够用的,但总有不一般的时候出现,所以,就增加了一个else
子句。其实,人类的自然语言何尝不是如此呢?总要根据需要添加不少东西。
>>> try:... print "I am try" #Python 3: print("I am try"),下同,从略... except:... print "I am except"... else:... print "I am else"... I am tryI am else
这段演示,能够帮助读者理解else的执行特点。如果执行了try
,则except
被忽略,但是else被执行。
>>> try:... print 1/0... except:... print "I am except"... else:... print "I am else"... I am except
这时候else就不被执行了。
理解了else的执行特点,可以写这样一段程序,还是类似于前面的计算,只是如果输入的有误,就不断要求从新输入,直到输入正确并得到了结果,才不再要求输入内容,然后程序结束。
在看下面的参考代码之前,读者是否可以先自己写一段并调试?看看结果如何。
Python 2:
#!/usr/bin/env python# coding=utf-8while 1: try: x = raw_input("the first number:") y = raw_input("the second number:") r = float(x)/float(y) print r except Exception, e: print e print "try again." else: break
Python 3:
#!/usr/bin/env python# coding=utf-8while 1: try: x = input("the first number:") y = input("the second number:") r = float(x)/float(y) print(r) except Exception as e: print(e) print("try again.") else: break
先看运行结果:
$ python 21703.pythe first number:2the second number:0 #异常,执行exceptfloat division by zerotry again. #循环the first number:2the second number:a #异常 could not convert string to float: atry again.the first number:4the second number:2 #正常,执行try2.0 #然后else:break,退出程序
相当满意的执行结果。
程序中的except Exception, e
或except Exception as e:
的含义是不管什么异常,这里都会捕获,并且传给变量e
,然后用print e
或者print(e)
把异常信息打印出来。
finally
finally
子句,一听这个名字,就感觉它是做善后工作的。的确如此,如果有了finally
,不管前面执行的是try
,还是except
,最终都要执行它。因此一种说法是将finally
用在可能的异常后进行清理。比如:
>>> x = 10>>> try:... x = 1/0... except Exception, e: #Python 3: except Exception as e:... print e #Python 3: print(e)... finally:... print "del x" #Python 3: print(e)... del x... integer division or modulo by zerodel x
看一看x
是否被删除?
>>> xTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'x' is not defined
当然,在应用中可以将上面的各个子句都综合起来使用,写成如下样式:
try: do somethingexcept: do somethingelse: do somethingfinally do something