你们得救是本乎恩,也因着信。这并不是出于自己,乃是神所赐的;也不是出于行为,免得有人自夸。(EPHESIANS 2:8-9)

错误和异常(2)

处理多个异常

try...except...是处理异常的基本方式。在此基础上,还可有扩展,能够处理多个异常。

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

Python 2:

#!/usr/bin/env python
# coding=utf-8

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:
            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-8

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:
            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:c
first number:3
second number:"hello"        #输入了一个不是数字的东西
please input number.         #对照上面的程序,捕获并处理了这个异常
************************
this is a division program.
input 'c' continue, otherwise logout:c
first number:4
second number:0
The 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:c
first number:2
second number:0           #捕获异常
please input rightly.
********************
this is a division program.
input 'c' continue, otherwise logout:c
first number:3
second 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:c
first number:2
second number:a                         #异常
could not convert string to float: a
********************
this is a division program.
input 'c' continue, otherwise logout:c
first number:2
second 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, eexcept 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 try
I 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-8
while 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-8
while 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.py
the first number:2
the second number:0        #异常,执行except
float division by zero
try again.                 #循环
the first number:2
the second number:a        #异常 
could not convert string to float: a
try again.
the first number:4
the second number:2        #正常,执行try
2.0                        #然后else:break,退出程序

相当满意的执行结果。

程序中的except Exception, eexcept 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 zero
del x

看一看x是否被删除?

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

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

try:
    do something
except:
    do something
else:
    do something
finally
    do something

总目录   |   上节:错误和异常(1)   |   下节:错误和异常(3)

如果你认为有必要打赏我,请通过支付宝:[email protected],不胜感激。

results matching ""

    No results matching ""