Python异常处理讲座
概述
异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。
一般情况下,在Python无法正常处理程序时就会发生一个异常。
异常是Python对象,表示一个错误。
当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。捕捉异常可以使用try语句。
【错误和异常官方文档
https://docs.python.org/zh-cn/3/tutorial/errors.html
https://docs.python.org/zh-cn/3/reference/executionmodel.html#exceptions
Python内置异常官网 https://docs.python.org/zh-cn/3/library/exceptions.html】
使用python编程的时候难免会出现各种各样的错误,这些错误会使程序中断。python解释器会告诉你错误发生在什么位置以及错误产生的原因,便于我们进行修改和调试。有时候我们并不希望这种错误中断程序的运行,比如在使用爬虫访问网站的时候,我们并不希望因为服务器未响应的问题导致爬虫程序出现异常继而中断,通过异常处理能够忽略本次异常让程序继续运行下去。
异常处理(exception handling)是一种错误处理( error handling)机制。
Python是一种解释型语言,没有编译这个环节,在实际执行代码才执行语法检查,发现语法是否正确。
在程序运行过程中,可能遇到各种各样的错误:
1.有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的。
2.有的错误是用户输入造成的,比如让用户输入email地址,结果得到一个空字符串,这种错误可以通过检查用户输入来做相应的处理。
3.还有一类错误是完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了,或者从网络抓取数据,网络突然断掉了。这类错误也称为异常,在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出。
try语句语法格式
一般语法格式:
try:
try语句块
except [异常名称 [ as 变量]]:
except语句块
else:
else语句块
finally:
finally语句块
上述异常语句的各子句的执行流程,参见下图:
其中,常见的异常名称(异常类型)如下:
AttributeError:属性错误,特性引用和赋值失败时会引发属性错误
NameError:试图访问的变量名不存在
SyntaxError:语法错误,代码形式错误
Exception:所有异常的基类,因为所有python异常类都是基类Exception的其中一员,异常都是从基类Exception继承的,并且都在exceptions python 模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。
IOError:一般常见于打开不存在文件时会引发IOError错误,也可以解理为输出输入错误。
KeyError:使用了映射中不存在的关键字(键)时引发的关键字错误。
IndexError:索引错误,使用的索引不存在,常索引超出序列范围。
TypeError:类型错误,内建操作或是函数应于在了错误类型的对象时会引发类型错误
ZeroDivisonError:除数为0,在用除法操作时,第二个参数为0时引发了该错误
ValueError:值错误,传给对象的参数类型不正确,像是给int()函数传入了字符串数据类型的参数。
AssertionError:当assert断言条件为假的时候抛出的异常。
【内置异常类的层次结构及异常名称可见https://docs.python.org/zh-cn/3/library/exceptions.html#exception-hierarchy
】
try语句按从简单结构到复杂结构包括的部分可分为:
try/except
try/except/else
try/except/else/finally
下面解说之。
try-except语法格式
try:
语句块1
except 异常名称:
语句块2
说明
这是最简单版的语法。
其中try- except关键字;ERRORTYPE是要监视的错误类型。
当我们认为某些代码(这里是语句块1)可能会出错时,就可以用try来运行这段代码(这里是语句块1),如果执行出错,则后续代码不会继续执行,而是跳转至错误处理代码,即except处执行,如果抛出的错误正好是except所监视的错误类型,就会执行语句块2,再执行完句块2后的代码。
try-except示例代码如下:
while True:
x=input("请输入一个数(输入a终止):")
if x == "a" :
print("终止")
break
try:
result = 5/float(x)
print("result is",result)
except ZeroDivisionError:
print("零不能做除数!")
print("--------------")
运行之,参见下图:
try-except-else语法格式
try:
语句块1
except 异常名称:
语句块2
else:
语句块3
try-except-else示例代码如下:
while True:
x=input("请输入一个数(输入a终止):")
if x == "a" :
print("终止")
break
try:
result = 5/float(x)
print("result is",result)
except ZeroDivisionError:
print("零不能做除数!")
else:
print("Re-result is",result)
print("--------------")
运行之,参见下图:
try-except- finally语法格式:
try:
语句块1
except 异常名称:
语句块2
finally:
语句块3
说明
执行try中的语句块1:
如果没有异常发生,则在执行finally之后程序退出
如果放生异常,并被except捕获,则执行except的语句块2,之后执行finally的语句块3,然后程序继续运行下去。
特别提示,如果存在finally子句,finally子句将作为try语句完成之前的最后一个任务执行。不管try语句是否产生异常,finally子句都会运行。
try-except- finally示例代码如下:
while True:
x=input("请输入一个数(输入a终止):")
if x == "a" :
print("终止")
break
try:
result = 5/float(x)
print("result is",result)
except ZeroDivisionError:
print("零不能做除数!")
finally:
print("进入 finally")
print("--------------")
运行之,参见下图:
try-except-else-finally语法格式
try:
语句块1
except 异常名称:
语句块2
else:
语句块3
finally:
语句块4
try-except-else-finally示例代码如下:
while True:
x=input("请输入一个数(输入a终止):")
if x == "a" :
print("终止")
break
try:
result = 5/float(x)
print("result is",result)
except ZeroDivisionError:
print("零不能做除数!")
else:
print("Re-result is",result)
finally:
print("进入 finally")
print("--------------")
运行之,参见下图:
补充说明:
不管try语句是否产生异常,finally子句都会运行。当try语句的任何其他子句通过break、continue或return语句离开时,finally子句也被执行。
finally子句是可选的;如果要出现finally;如果异常没有被except子句捕获,或者异常发生在except或else子句内,finally子句执行完毕后,会将此异常抛出。
except语句后面如果不指定异常类型,则默认捕获所有异常。
except语句可以有多个,Python会按except语句的顺序依次匹配你指定的异常,如果异常已经处理就不会再进入后面的except语句。
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:except (RuntimeError, TypeError, NameError)。
else子句是可选的;如果要出现else子句,必须在所有except子句之后。
except 子句可以在异常名称后面指定一个变量。这个变量和一个异常实例绑定。在Python中,异常也是对象【大多数开发人员将实例(Instance)和对象(Object)视为同义词】,可对它进行操作。所有异常都从基类exception继承,当不确定是哪种异常时,可以使用它,了解情。例如:
try:
1/0
except Exception as et:
print("et.args: ", et.args) # arguments stored in .args
print("er: ", et)
print("type(et): ", type(et)) # the exception instance
运行之,输出如下:
还可以使用raise语句或assert语句主动生成异常。其中raise可以直接抛出某个异常,assert需要通过布尔值来判断,然后再抛出给定的AssertionError。
raise 语句
raise 语句允许程序员强制引发指定的异常,即用 raise 语句可手动引发的异常。
raise 语句的基本语法格式为:
raise [exceptionName [(reason)]]
其中,exceptionName表示你给出的异常名称,reason表示给出的异常描述信息; [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出。
例、判断接收到的字符串是否为数字
try:
a = input("输入一个整数:")
#判断用户输入的是否为整数
if(not a.isdigit()):
raise ValueError("a 必须是整数") #引发异常
except ValueError as et:
print("异常:",repr(et))
【提示:python判断用户从键盘输入情况,例如:
str =input("please input the number:")
str.isalnum() 若所有字符都是数字或者字母则为True,否则为False
str.isalpha() 若所有字符都是字母则为True,否则为False
str.isdigit() 若所有字符都是数字则为True,否则为False
str.islower() 若所有字符都是小写则为True,否则为False
str.isupper() 若所有字符都是大写则为True,否则为False
str.istitle() 若所有单词都是首字母大写则为True,否则为False
str.isspace() 若所有字符都是空白字符、\t、\n、\r则为True,否则为False
】
运行之,参见下图:
当用户输入的不是数字时,程序会进入 if 判断语句,并执行 raise 引发 ValueError 异常。但由于其位于 try 块中,因为 raise 抛出的异常会被 try 捕获,并由 except 块进行处理。
下面的例子,和上例相比,仅有一处不同,添加了一句位于 except 块中的不带参数的 raise:
try:
a = input("输入一个整数:")
#判断用户输入的是否为整数
if(not a.isdigit()):
raise ValueError("a 必须是整数") #引发异常
except ValueError as et:
print("异常:",repr(et))
raise #再引发一次异常
运行之,参见下图:
重点关注位于 except 块中的 raise,由于在其之前我们已经手动引发了 ValueError 异常,因此这里当再使用 raise 语句时,它会再次引发一次。
当在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如
try:
a = input("输入一个整数:")
#判断用户输入的是否为整数
if(not a.isdigit()):
raise
except ValueError as et:
print("异常:",repr(et))
运行之,参见下图:
在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。
assert(断言)语句
格式:
assert 表达式 [,参数]
assert语句用来声明某个条件是真的。
当assert语句的表达式为False,会引发异常AssertionError。
是一种调式(debugging)手段。
assert condition
逻辑上等同于:
if not condition:
raise AssertionError()
下面这段代码用来检测数据类型的断言,因为 a_str 是 str 类型,所以认为它是 int 类型肯定会引发错误。
a_str = 'this is a string'
assert type(a_str) == int
运行之,参见下图:
assert 会令程序崩溃,为什么还要使用它呢?这是因为,与其让程序在晚些时候崩溃,不如在错误条件出现时,就直接让程序崩溃,这有利于我们对程序排错,提高程序的健壮性。assert 语句通常用于检查用户的输入是否符合规定,还经常用作程序初期测试和调试过程中的辅助工具。如:
mathmark = float(input("请输入数学考试分数"))
#断言数学考试分数是否位于正常范围内
assert 0.0 <= mathmark <= 150.0
#只有当 mathmark 位于 [0,100]范围内,程序才会继续执行
print("数学考试分数为:",mathmark)
如果你输入的数学考试分数在[0.0 ~ 150.0],正常输出分数:
如果你输入的数学考试分数在[0.0 ~ 150.0],正常输出分数:
若超出范围报错:
用户自定义异常
实际开发中,有时候系统提供的异常类型不能满足开发的需求。这时候你可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承。例、
class TooLongExceptin(Exception):
'''用户名的长度异常'''
def __init__(self,leng):
self.leng = leng
def __str__(self):
print("姓名长度是"+str(self.leng)+",超过长度了")
#2.手动抛出用户自定义类型异常
def name_Test():
name = input("请输入名字:")
if len(name)>4:
raise TooLongExceptin(len(name)) #抛出异常很简单,使用raise即可,但是没有处理,即捕捉
else :
print("你输入的名字是",name)
#调用函数,执行
name_Test()
运行之,参见下图: