Python基础篇——Day9
异常
异常的本质
异常是指程序运行过程中出现的非正常现象,例如用户输入错误,除数为零,需要处理的文件不存在,数组下标越界等
异常处理
所谓异常处理,就是指程序在出现问题时依然可以正确的执行剩余的程序,而不是因为异常而终止执行
异常处理过程:
- 抛出异常:在程序执行时,若出现异常,则会生成代表该异常的一个对象,停止当前执行路径,并把异常对象交给解释器
- 捕获异常:解释器得到该异常后,寻找相应的代码处理该异常
异常类
Python中,引进了很多用来描述和处理异常的类,称为异常类。异常类定义中包含了该类异常的信息和对异常进行处理的方法。Python中异常类的继承层次如下:
BaseException:所有异常的父类
KeyBoardInterrupt, Exception,SystemExit,GeneratorExit:BaseException的子类
NameError,ValueError,AttributeError等:Exception类的子类
try…except结构
单个except结构
try…except是常见的异常处理结构,结构如下:
try:
被监控的可能引发异常的语句块
except BaseException [as e]:
异常处理语句块
'''
1. BaseException表示所有异常的父类,写在这肯定没错,但也可以根据不同的异常类型选择对应的异常子类,如Exception类
2. 也可省略except后面的异常类型,即,用一个except来捕获所有可能的异常
'''
- try语句块包含着可能引发异常的代,except块用来捕捉和处理发生的异常
- 执行时,如果try语句块中无异常,则跳过except继续执行后续代码,
- 执行时,若try语句块中出现异常,则跳过try语句块中的后续代码,跳到相应的except块中处理异常
- 异常处理完后,继续执行后续代码
操作示例:
try:
print("step1")
a=3/0
print("step2")
except BaseException as e:
print("step3")
print(e)
print("step4")
'''
结果为:
step1
step3
division by zero
step4
多个except结构
上面的单个except结构可以捕获所有的异常,工作中也很常见。但是从经典理论考虑,一般建议捕获可能出现的多个异常(按照先子类后父类的顺序),并且针对性地写出异常处理代码。为了避免遗漏可能出现的异常,可在最后增加BaseException,多except结果如下:
try:
被监控的,可能引发异常的语句块
except Exception1:
处理Exception1的语句块
except Exception2:
处理Exception2的语句块
...
exception BaseException:
处理可能遗漏的异常语句块
操作示例:
try:
a=input("输入一个被除数")
b=input("输入一个除数")
c=float(a)/float(b)
except ZeroDivisionError:
print("不能除以0")
except ValueError:
print("不能有字符串")
except NameError:
print("变量不存在")
except BaseException as e:
print(e)
else语句
在try…except语句块中增加了else语句块,如果try中未抛出异常,则执行else语句块,如果有异常,则执行except语句块,不执行else块
操作示例:
try:
a=input("输入被除数")
b=input("输入除数")
c=float(a)/float(b)
except BaseException as e:
print(e)
else:
print("结果为:",c)
finally
try…except…finally语句块中,无论try中有没有异常,finally中的语句都会被执行
操作示例:
try:
f=open(r"E:\d.txt","r")
a=f.readline()
print(a)
except:
print("文件未找到")
finally:
print("关闭资源")
try:
f.close()
except BaseException as e:
print(e)
print("程序执行结束")
'''
注意:在finally语句块中还存在try...except语句,这是因为如果文件路径未找到,则在执行f.close()语句时会出现异常,导致无法执行打印"程序执行结束"的操作,故需再次执行异常判断的操作以保证所有程序均可正常执行
'''
return语句和异常处理问题
由于return有两种作用,结束方法运行、返回值。但是一般不把return放到异常处理结构中,而是放到方法最后
操作示例:
def test():
print("step1")
try:
x=3/0
except:
print("step2")
print("不能把0做除数")
finally:
print("step4")
print("step5")
return "e"
'''
一般不要将return放在try,except,finally语句块中,会发生一些意想不到的错误,建议放方法最后
'''
常见异常
- SyntaxError:语法错误
- NameError:尝试访问一个没有被定义的变量
- ZeroDivisionError:除数为0的错误
- ValueError:数值错误
>>>float("a")
ValueError: could not convert string to float: 'a'
- TypeError:类型错误
>>>123+"abc"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
- AttributeError:访问对象不存在的属性
>>>a=100
>>>a.x()
AttributeError: 'int' object has no attribute 'x'
- IndexError:索引越界异常
- KeyError:字典的关键字不存在
- FileNotFoundError:未找到指定文件
with上下文管理
finally块由于是否发生异常都会被执行,通常用于存放释放资源(如关闭文件)的代码,但其实我们可以通过with上下文管理,更方便的实现释放资源的操作
with上下文管理的语法结构如下:
with context_expr [as var]:
语句块
with上下文管理可以自动管理资源,在with代码块执行完毕后自动还原进入该代码之前的情形。不论何种原因跳出with块,无论是否有异常,总能保证资源正常释放。故其在文件操作,网络通信等场合非常实用
操作示例:
'''
注意:with不是用来取代try...except...finally结构的,而是作为一种补充,方便管理
'''
with open(r"E:\a.txt","r") as f:
a=f.readline()
print(a)
print("程序执行结束")
traceback模块
操作示例:
import traceback
try:
print("step1")
num=1/0
except:
traceback.print_exc() #打印异常信息
step1
Traceback (most recent call last):
File "E:\Python36\aa.py", line 4, in <module>
num=1/0
ZeroDivisionError: division by zero
'''
将异常信息输出到指定的文件中
'''
try:
print("step1")
num=1/0
except:
# 以追加模式(a)打开文件
with open(r"E:\a.txt","a") as f:
traceback.print_exc(file=f)
自定义异常类
- 程序开发中,可以自定义异常类,自定义异常类一般都是运行时异常,通常继承Exception或其子类即可,命名一般以Error,Exception为后缀
- 自定义异常由raise语句主动抛出
操作示例:
# 测试自定义异常类
# 继承Exception类
class AgeError(Exception):
def __init__(self,errorInfo):
Exception.__init__(self)
self.errorInfo=errorInfo
def __str__(self): # 用于描述类信息
return "年龄错误"
# 如果为True,则模块是作为独立文件运行,可以执行测试代码
if __name__ == "__main__":
age = int(input("输入年龄:")
if (age<0) or (age>130):
raise AgeError()
else:
print("ok!")