(2) 自定义异常类
Python已经为使用者提供了丰富的内建异常类,它们可以满足大部分的需求。但有些时候,程序员需要使用自己定义的异常,这时也可以创建自己的异常类。和内建异常类一样,用户自定义的异常类应该典型的继承自Exception类,可以通过直接或者间接的方式。自定义的异常类常使用raise语句引发,而且只能通过人工方式触发。
编写一个自定义异常类的基本方式为:
>>> class CustomError(Exception):
... pass
...
定义了这个异常,程序中就可以使用raise来触发这个异常了,如下面代码:
>>> raise CustomError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__. CustomError
例1:自定义传参异常
#py6-1.py
class MyError(Exception): |
def __init__(self,value): |
super(MyError,self).__init__ (value) |
self.value=value |
raise MyError,"Error Information" |
运行结果:
Traceback (most recent call last):
File "py6-1.py", line 6, in <module>
raise MyError,"Error Information"
__main__.MyError: Error Information
python编程中,为了使程序能够不崩溃并且正确运行,需要对异常进行捕获和处理。这一节中将讲解捕获异常的几种方法。
(一)try-except语句
(1) try-except语句形式
用try-except语句捕获处理异常时,将可能出现异常的语句放到try子句的代码块中,将处理异常的语句放入except子句的代码块中。try-except语句的一般形式为:
try:
try block
except Exception[, reason]:
exception block
上面代码的工作方式为:首先执行try子句中的代码块。如果没有发生任何异常,except子句中的代码会在try语句执行完之后被忽略掉。如果执行try子句中的代码时引发了异常,那么try代码块中引发这个异常的后面的代码就会被忽略掉。如果引发的异常与except关键字后面的指定异常类型相匹配,那么就跳转到这个except子句中执行except代码块的语句。如果try语句中引发的异常在except子句中没有与它匹配的分支,它会传递到上一级的try语句中。如果最终仍找不到与之匹配的except语句,它就会成为一个未处理异常,这时程序会终止运行,并提示异常信息。
注意:except子句可以没有接任何异常和异常参数,这时try语句捕获的任何异常都会交给except子句中的代码块来处理。
(2)try-except-else结构
与条件语句和循环语句类似,else语句也可以应用到异常捕获中。它可以和try-except语句一起组成try-except-else的结构。如下面代码:
myfile=open('myfile.txt','w')
except:
print('myfile open failed.')
else:
print( 'myfile open successfully.')
myfile.close()
这个语句结构的工作方式为:如果程序在try范围内捕获到了except语句指定的异常,就跳转到except语句中继续执行;如果try范围内没有捕获到任何异常,就执行else语句中的代码块。
(3)异常参数
在try-except的一般形式中可以看到except语句中指定异常类型的后面有一个可选参数reason,这个reason就是用来保存异常参数的变量。还以除0错误为例,如下面代码所示:
>>> try:
... 1/0
... except ZeroDivisionError,e:
... print e
输出结果:integer division or modulo by zero
上面程序中的e即为接收异常参数的变量,在except代码块中直接输出e,可以看到输出的结果即为引发异常的原因。
例2:计算输入的两个整数相除的结果
问题分析:依次提示输入两个整数x和y,如果y的值为零,提示重新输入两个数,否则计算并打印x除以y的值。
#py6-2.py 例 计算输入的两个数相除的结果
print('计算输入的两个数相除的结果')
while True:
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
print(x / y)
break
except ZeroDivisionError:
print('The second number cannot be zero!')
运行:
计算输入的两个数相除的结果
Enter the first number: 5
Enter the second number: 0
The second number cannot be zero!
Enter the first number: 4
Enter the second number: 5
0.8
(二) 捕获多种异常
在编写程序时,往往一段代码所引发的异常不只一种,如例2中,当做如下输出时,对应的运行结果为:
计算输入的两个数相除的结果
Enter the first number: 5
Enter the second number: a
Traceback (most recent call last):
File "C:/Users/86158/Desktop/22HX-Python/HX计应班(Python 程序设计)/单元6 异常处理/pyprg6/py6-2.py", line 7, in <module>
y = int(input('Enter the second number: '))
ValueError: invalid literal for int() with base 10: 'a'
当输入y的值时,错误得输入了一个字母“a”时,程序报出了一个NameError错误。虽然这段代码在try语句中,但因为except语句中没有指定捕捉NameError这种异常,造成程序报错并中断运行。这时就需要捕捉多种异常的语句。
(1)带有多个except的try语句
带多个except的try语句的工作方式为:首先尝试执行try子句,如果没有错误,则忽略所有except语句。如果引发某种异常,程序会依次在except语句中寻找与引发异常类型相匹配的异常。如果找到,会跳转到该except语句中,否则继续向下寻找。如果都没有找到,则会将异常传递给上一层try语句。
例3:计算输入的两个数相除的结果
#例py6-3.py 计算输入的两个数相除的结果
print('计算输入的两个数相除的结果')
while True:
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
print(x / y)
break
except ValueError:
print('Please input a digit!')
except ZeroDivisionError:
print('The second number cannot be zero!')
一个except块捕捉多个异常
try:
num1 = int(input('Enter the first number: '))
num2 = int(input('Enter the second number: '))
print(num1 / num2)
except (ValueError, ZeroDivisionError):
print('Invalid input!')
#例py6-4.py 计算输入的两个数相除的结果
print('计算输入的两个数相除的结果')
while True:
try:
num1 = int(input('Enter the first number: '))
num2 = int(input('Enter the second number: '))
print(num1 / num2)
break
except : # 捕捉所有可能的异常, 一了百了 空except
print(' Something went wrong! again input!')
(2) as 子句
try:
被检测的语句块
except 异常类名 as 错误原因名:
异常处理语句块
print(错误原因名)
#例py6-5.py 计算输入的两个数相除的结果
print('计算输入的两个数相除的结果')
while True:
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
print(x / y)
break
except ValueError as e1:
print(e1,'Please input a digit!')
except ZeroDivisionError as e2:
print(e2,'The second number cannot be zero!')
试运行:
计算输入的两个数相除的结果
Enter the first number: q
invalid literal for int() with base 10: 'q' Please input a digit!
Enter the first number: ,
invalid literal for int() with base 10: ',' Please input a digit!
Enter the first number: 8
Enter the second number: w
invalid literal for int() with base 10: 'w' Please input a digit!
Enter the first number: 4
Enter the second number: 0
division by zero The second number cannot be zero!
Enter the first number: 6
Enter the second number: 3
2.0
(3)else子句
#例py6-6.py 计算输入的两个数相除的结果
print('计算输入的两个数相除的结果')
while True:
try:
num1 = int(input('Enter the first number: '))
num2 = int(input('Enter the second number: '))
print(num1 / num2)
except ValueError as e1:
print(e1,'Please input a digit!')
except ZeroDivisionError as e2:
print(e2,'The second number cannot be zero!')
else:
print('Haha, I am smart.')
break
# Filename: py6-7.py 注意breaky语句的位置及作用
aList = [1, 2, 3, 4, 5]
i = 0
while True:
try:
print(aList[i])
except IndexError:
print('index error')
break
else:
i += 1
(4)finally子句
# Filename: py6-8.py 注意final 子句的作用
def finallyTest():
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
print(x / y)
return 1
except Exception as err:
print(err)
return 0
finally:
print('It is a finally clause.')
result = finallyTest()
print(result)
# py6-9.py 应用示例 提取文本中的数字字符串转化成浮点数,并累加。
def isfloat(s):
if s[-1] == '.':
s = s.strip('.')
try:
float(s)
except ValueError:
return False
return float(s)
if __name__ =="__main__":
text = input('Please input the strings:\n')
for ch in text:
if ch in ',':
text = text.replace(ch, '')
words = text.split()
print(words)
s=0
found = 0
for word in words:
if isfloat(word) !=False:
print('--', isfloat(word))
s=s+float(isfloat(word))
found = 1
if found == 0:
print('Not Found!')
print('sum= ',s)
运行:
Please input the strings:
book is 3.4 5 6 2 3.6 2.3 6.
['book', 'is', '3.4', '5', '6', '2', '3.6', '2.3', '6.']
-- 3.4
-- 5.0
-- 6.0
-- 2.0
-- 3.6
-- 2.3
-- 6.0
sum= 28.3
(5)上下文管理器(Context Manager)和with语句
上下文管理器
定义和控制代码块执行前的准备动作及执行后的收尾动作
通过with语句在支持上下文管理协议的对象(如文件对象)上方便地进行使用
# py6-10.py
with open('data.txt') as f:
for line in f:
print(line, end='')
格式: with 上下文管理表达式 as 变量:
语句序列
例:计算一个文件的行数
# Filename: py6-11.py
def countLines(fname):
try:
with open(fname) as f:
data = f.readlines()
except FileNotFoundError:
print(fname + ' does not exist')
else:
lens = len(data)
print(fname + ' has ' + str(lens) + ' lines')
#if __name__ == ' __main__ ' :
fname = 'data.txt'
countLines(fname)
说明:如果文件data.txt不存在,则执行结果为:
data.txt does not exist
若文件data.txt存在,则统计其行数并输出统计结果,执行结果示意如下:
data.txt has 16 lines

