第九天
今天我们来说下Python中的异常,以及如何去处理异常。我们在程序编码中难免会碰到异常,今天我们就要来简要说明什么是异常,如何处理异常。
1、异常的定义
不论是Python语言、Java语言以及其他任何语言,程序在执行的过程中难免会产生的错误,这些错误都可以称之为异常。比如列表索引越界、打开不存在的文件等。
就如同下面两行代码:
print(str1)
# name 'str1' is not defined
open('error.txt','r')
# No such file or directory: 'error.txt'
2、异常处理
程序中出现异常是难免的,发生异常时我们需要捕获处理它,否则程序会终止执行。
如下代码:
#控制台输入两个数字 求商
print('程序开始')
num1 = int(input('请输入除数'))
num2 = int(input('请输入被除数'))
print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
print('程序结束')
上述这段代码其实就是存在问题的,比如我在获得数字num1的时候输入的内容不可以转换为int(比如你输入wasd),这个时候就出现异常了。
ValueError: invalid literal for int() with base 10: 'wasd'
其实就是将非数字字符串转换为整型出现的异常;
如果你在获得num2的时候,如果输入了0也会出现异常,
ZeroDivisionError: division by zero
其实就是除以0的原因导致的。
并且我们发现上述两种异常任何一种异常出现,我们的程序就停止了,并且程序没有往下执行,因为我们在控制台看不到最后一行print的输出。
这时候就需要我们异常处理了。
2.1、异常类
在Python中,所有异常都是基类Exception的成员,它们都定义在exceptions模块中。
如果这个异常对象没有进行处理和捕捉,程序就会用所谓的回溯(traceback,一种错误信息)终止执行,这些信息包括错误的名称(例如NameError)、原因和错误发生的行号。下面简单说下我们经常遇见的几个异常:
1、NameError
尝试访问一个未声明的变量,会引发NameError。
print(str1)
# NameError: name 'str1' is not defined
2、ZeroDivisionError
当除数为零的时候,会引发ZeroDivisionError异常。
a = 10/0
print(a)
# ZeroDivisionError: division by zero
**3、SyntaxError **
当解释器发现语法错误时,会引发SyntaxError异常。
a = 10
if a == 10
print('宾果!')
# SyntaxError: invalid syntax
4、IndexError
当使用序列中不存在的索引时,会引发IndexError异常。
list = [1,2,3,4]
a = list[4]
print(a)
# IndexError: list index out of range
5、KeyError
当使用映射中不存在的键时,会引发KeyError异常。
mydict = {'name':'张三','age':18}
address = mydict['address']
print(address)
# KeyError: 'address'
**6、FileNotFoundError **
试图打开不存在的文件时,会引发FileNotFoundError。
file = open('a.txt','r')
# FileNotFoundError: [Errno 2] No such file or directory: 'a.txt'
7、AttributeError
当尝试访问未知对象属性时,会引发AttributeError异常。
class Settings():
def _init_(self):
self.scren_width=1200
self.screen_height=800
self.bg_color=(230,230,230)
if __name__ == '__main__':
a = Settings()
print(a.scren_width)
# AttributeError: 'Settings' object has no attribute 'scren_width'
2.2、异常处理
在python中,try-except语句定义了监控异常的一段代码,并提供了处理异常的机制。
1、捕获指定异常
try:
# 可能会出现异常的语句块
except <异常种类>:
# 异常处理代码
print('程序开始')
try:
a = 10/0
print(a)
except ZeroDivisionError as e:
print('捕获异常-零不可以是除数',e)
print('程序继续执行')
# 程序开始
# 捕获异常-零不可以是除数 division by zero
# 程序继续执行
注意,exception后捕获的异常必须和try代码块中出现的异常种类一致,才可以捕获,否则依然会出现异常,影响其后代码的执行。
print('程序开始')
try:
a = 10/0
print(a)
except FileNotFoundError as e:
print('捕获异常-文件找不到',e)
print('程序继续执行')
# ZeroDivisionError: division by zero
2、捕获多个异常
捕获多个异常有两种方式,第一种是一个except同时处理多个异常,不区分优先级。
try:
# 可能会出现异常的语句块
except (<异常名1>, <异常名2>, ...):
# 异常处理代码
print('程序开始')
try:
num1 = int(input('请输入除数'))
num2 = int(input('请输入被除数'))
print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
except (ZeroDivisionError,ValueError):
print('出现异常了')
print('程序继续执行')
还有第二种方式,是区分优先级的。
try:
# 可能会出现异常的语句块
except <异常种类1>:
# 异常处理代码1
except <异常种类2>:
# 异常处理代码2
except <异常种类3>:
# 异常处理代码3
print('程序开始')
try:
num1 = int(input('请输入除数'))
num2 = int(input('请输入被除数'))
print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
except ZeroDivisionError as e1:
print('出现异常了',e1)
except ValueError as e2:
print('出现异常了',e2)
print('程序继续执行')
3、异常中的else
如果try语句没有捕获到任何的错误信息,就不再执行任何except语句,而是会执行else语句。
try:
# 可能会出现异常的语句块
except <异常种类1>:
# 异常处理代码1
except <异常种类2>:
# 异常处理代码2
except <异常种类3>:
# 异常处理代码3
else:
# try语句中没有异常则执行此段代码
import os
print('程序开始执行')
try:
wfile = open('2.txt','w',encoding='utf-8')
wfile.write('这是测试文件写入的内容')
except IOError as e:
print('IO异常',2)
else:
print('内容写入成功')
wfile.close()
print('程序继续执行')
# 程序开始执行
# 内容写入成功
# 程序继续执行
4、捕获所有的异常
当程序中出现大量异常时,捕获这些异常是非常麻烦的。这时,我们可以在except子句中不指明异常的类型,这样,不管发生何种类型的异常,都会执行except里面的处理代码。
print('程序开始')
try:
num1 = int(input('请输入除数'))
num2 = int(input('请输入被除数'))
print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
except:
print('出现异常了')
print('程序继续执行')
5、终止行为(finally)
在程序中,无论是否捕捉到异常,都必须要执行某件事情,例如关闭文件、释放锁等,这时可以提供finally语句处理。通常情况下,finally用于释放资源。
str = 'hello python'
try:
a = int(str)
except IndexError as e1:
print('出现异常',e1)
except KeyError as e2:
print('出现异常',e2)
except ValueError as e3:
print('出现异常',e3)
else:
print('try内没有异常')
finally:
print('无论异常与否,都会执行我')
3、raise语句
python是否可以在程序的指定位置手动抛出一个异常?答案是肯定的,python 允许我们在程序中手动设置异常,使用 raise 语句即可。类似Java中的throw。
语法:raise [exceptionName [(reason)]]
其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。
简而言之就是使用raise语句能显示地触发异常。
格式如下:
1、raise 异常类名 引发指定异常类的实例
2、raise 异常类对象 引发指定异常类的实例
3、raise 重新引发刚刚发生的异常
3.1、使用类名引发异常
print('程序开始执行')
try:
a = input('请输入一个数字')
#判断用户输入的是否为数字
if(not a.isdigit()):
raise ValueError("输入的必须是数字") #人为扔出异常
except ValueError as e:
print("引发异常:",repr(e))
print('程序继续执行')
# 程序开始执行
# 请输入一个数字wasd
# 引发异常: ValueError('输入的必须是数字')
# 程序继续执行
3.2、使用异常类的实例引发异常
print('程序开始执行')
try:
a = input('请输入一个数字')
#判断用户输入的是否为数字
if(not a.isdigit()):
err = ValueError()
raise err
except ValueError as e:
print("引发异常:",repr(e))
print('程序继续执行')
3.3、raise传递异常
不带任何参数的raise语句,可以再次引发刚刚发生过的异常,作用就是向外传递异常。
print('程序开始执行')
try:
a = input('请输入一个数字')
#判断用户输入的是否为数字
if(not a.isdigit()):
raise ValueError("输入的必须是数字")
except ValueError as e:
print("引发异常:",repr(e))
raise
print('程序继续执行')
# ValueError: 输入的必须是数字
4、assert语句
assert语句又称作断言,指的是期望用户满足指定的条件。
当用户定义的约束条件不满足的时候,它会触发AssertionError异常,所以assert语句可以当做条件式的raise语句。
assert语句格式如下:
assert 逻辑表达式,data
相当于:
if not 逻辑表达式:
raise AssertionError(data)
assert后面紧跟一个逻辑表达式,相当于条件。Data通常是一个字符串,当条件为false时作为异常的描述信息。
print('程序开始执行')
a = int(input('请输入除数'))
assert a != 0,'除数不可以为0'
# AssertionError: 除数不可以为0
5、自定义异常
python允许我们自定义异常,只需要两步:
1、创建一个继承Exception类的子类,就是自定义异常类。
2、当遇到自己设定的错误时,使用raise语句抛出自定义的异常。
#自定义异常类
class MyErr(Exception):
def __init__(self,args):
self.args = args
#触发自定义异常
if __name__ == '__main__':
print('程序开始执行')
try:
raise MyErr('这是我自定义的异常')
except MyErr as e:
print('出现的异常为',e.args)
6、总结
这次主要针对Python的异常进行介绍,包括异常类、抛出和捕捉系统内置的异常、抛出和捕捉自定义异常,大家应该深入了解了异常产生的原理,并知道如何在程序中运行它们。
网友评论