错误和异常 (2)

try…except…是处理异常的基本方式。在原来的基础上,还可有扩展。

处理多个异常

处理多个异常,并不是因为同时报出多个异常。程序在运行中,只要遇到一个异常就会有反应,所以,每次捕获到的异常一定是一个。所谓处理多个异常的意思是可以容许捕获不同的异常,有不同的 except 子句处理。

  1. #!/usr/bin/env Python
  2. # coding=utf-8
  3. while 1:
  4. print "this is a division program."
  5. c = raw_input("input 'c' continue, otherwise logout:")
  6. if c == 'c':
  7. a = raw_input("first number:")
  8. b = raw_input("second number:")
  9. try:
  10. print float(a)/float(b)
  11. print "*************************"
  12. except ZeroDivisionError:
  13. print "The second number can't be zero!"
  14. print "*************************"
  15. except ValueError:
  16. print "please input number."
  17. print "************************"
  18. else:
  19. break

将上节的一个程序进行修改,增加了一个 except 子句,目的是如果用户输入的不是数字时,捕获并处理这个异常。测试如下:

  1. $ python 21701.py
  2. this is a division program.
  3. input 'c' continue, otherwise logout:c
  4. first number:3
  5. second number:"hello" #输入了一个不是数字的东西
  6. please input number. #对照上面的程序,捕获并处理了这个异常
  7. ************************
  8. this is a division program.
  9. input 'c' continue, otherwise logout:c
  10. first number:4
  11. second number:0
  12. The second number can't be zero!
  13. *************************
  14. this is a division program.
  15. input 'c' continue, otherwise logout:4
  16. $

如果有多个 except,在 try 里面如果有一个异常,就转到相应的 except 子句,其它的忽略。如果 except 没有相应的异常,该异常也会抛出,不过这是程序就要中止了,因为异常“浮出”程序顶部。

除了用多个 except 之外,还可以在一个 except 后面放多个异常参数,比如上面的程序,可以将 except 部分修改为:

  1. except (ZeroDivisionError, ValueError):
  2. print "please input rightly."
  3. print "********************"

运行的结果就是:

  1. $ python 21701.py
  2. this is a division program.
  3. input 'c' continue, otherwise logout:c
  4. first number:2
  5. second number:0 #捕获异常
  6. please input rightly.
  7. ********************
  8. this is a division program.
  9. input 'c' continue, otherwise logout:c
  10. first number:3
  11. second number:a #异常
  12. please input rightly.
  13. ********************
  14. this is a division program.
  15. input 'c' continue, otherwise logout:d
  16. $

需要注意的是,except 后面如果是多个参数,一定要用圆括号包裹起来。否则,后果自负。

突然有一种想法,在对异常的处理中,前面都是自己写一个提示语,发现自己写的不如内置的异常错误提示更好。希望把它打印出来。但是程序还能不能中断。Python 提供了一种方式,将上面代码修改如下:

  1. while 1:
  2. print "this is a division program."
  3. c = raw_input("input 'c' continue, otherwise logout:")
  4. if c == 'c':
  5. a = raw_input("first number:")
  6. b = raw_input("second number:")
  7. try:
  8. print float(a)/float(b)
  9. print "*************************"
  10. except (ZeroDivisionError, ValueError), e:
  11. print e
  12. print "********************"
  13. else:
  14. break

运行一下,看看提示信息。

  1. $ python 21702.py
  2. this is a division program.
  3. input 'c' continue, otherwise logout:c
  4. first number:2
  5. second number:a #异常
  6. could not convert string to float: a
  7. ********************
  8. this is a division program.
  9. input 'c' continue, otherwise logout:c
  10. first number:2
  11. second number:0 #异常
  12. float division by zero
  13. ********************
  14. this is a division program.
  15. input 'c' continue, otherwise logout:d
  16. $

在 Python3.x 中,常常这样写:except (ZeroDivisionError, ValueError) as e:

以上程序中,之处理了两个异常,还可能有更多的异常呢?如果要处理,怎么办?可以这样:execpt: 或者 except Exception, e,后面什么参数也不写就好了。

else 子句

有了 try…except…,在一般情况下是够用的,但总有不一般的时候出现,所以,就增加了一个 else 子句。其实,人类的自然语言何尝不是如此呢?总要根据需要添加不少东西。

  1. >>> try:
  2. ... print "I am try"
  3. ... except:
  4. ... print "I am except"
  5. ... else:
  6. ... print "I am else"
  7. ...
  8. I am try
  9. I am else

这段演示,能够帮助读者理解 else 的执行特点。如果执行了 try,则 except 被忽略,但是 else 被执行。

  1. >>> try:
  2. ... print 1/0
  3. ... except:
  4. ... print "I am except"
  5. ... else:
  6. ... print "I am else"
  7. ...
  8. I am except

这时候 else 就不被执行了。

理解了 else 的执行特点,可以写这样一段程序,还是类似于前面的计算,只不过这次要求,如果输入的有误,就不断要求从新输入,知道输入正确,并得到了结果,才不再要求输入内容,程序结束。

在看下面的参考代码之前,读者是否可以先自己写一段呢?并调试一下,看看结果如何。

  1. #!/usr/bin/env Python
  2. # coding=utf-8
  3. while 1:
  4. try:
  5. x = raw_input("the first number:")
  6. y = raw_input("the second number:")
  7. r = float(x)/float(y)
  8. print r
  9. except Exception, e:
  10. print e
  11. print "try again."
  12. else:
  13. break

先看运行结果:

  1. $ python 21703.py
  2. the first number:2
  3. the second number:0 #异常,执行 except
  4. float division by zero
  5. try again. #循环
  6. the first number:2
  7. the second number:a #异常
  8. could not convert string to float: a
  9. try again.
  10. the first number:4
  11. the second number:2 #正常,执行 try
  12. 2.0 #然后 else:break,退出程序
  13. $

相当满意的执行结果。

需要对程序中的 except 简单说明,这次没有像前面那样写,而是 except Exception, e,意思是不管什么异常,这里都会捕获,并且传给变量 e,然后用 print e 把异常信息打印出来。

finally

finally 子句,一听这个名字,就感觉它是做善后工作的。的确如此,如果有了 finally,不管前面执行的是 try,还是 except,它都要执行。因此一种说法是用 finally 用来在可能的异常后进行清理。比如:

  1. >>> x = 10
  2. >>> try:
  3. ... x = 1/0
  4. ... except Exception, e:
  5. ... print e
  6. ... finally:
  7. ... print "del x"
  8. ... del x
  9. ...
  10. integer division or modulo by zero
  11. del x

看一看 x 是否被删除?

  1. >>> x
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. NameError: name 'x' is not defined

当然,在应用中,可以将上面的各个子句都综合起来使用,写成如下样式:

  1. try:
  2. do something
  3. except:
  4. do something
  5. else:
  6. do something
  7. finally
  8. do something

和条件语句相比

try…except…在某些情况下能够替代 if…else.. 的条件语句。这里我无意去比较两者的性能,因为看到有人讨论这个问题。我个人觉得这不是主要的,因为它们之间性能的差异不大。主要是你的选择。一切要根据实际情况而定,不是说用一个就能包打天下。


总目录

如果你认为有必要打赏我,请通过支付宝:qiwsir@126.com,不胜感激。