一、概念
就是程序运行时发生错误的信号。
当 Python 检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常"。
二、常见种类
1、AttributeError
试图访问一个对象没有的属性,比如 test.x,但是 test 没有属性 x。
2、IOError
输入或输出异常,基本上是无法打开文件。
3、ImportError
无法引入模块或包,基本上是路径问题或名称错误。
4、IndentationError
语法错误(的子类),代码没有正确对齐。
5、IndexError
下标索引超出序列边界,比如当 x 只有三个元素,却试图访问 x[5]。
6、KeyError
试图访问字典里不存在的键。
7、NameError
使用一个还未被赋予对象的变量。
8、SyntaxError
Python 代码非法,代码不能编译(语法错误,写错了)。
9、TypeError
传入对象类型与要求的不符合。
10、UnboundLocalError
试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它。
11、ValueError
传入一个调用者不期望的值,即使值的类型是正确的。
三、处理
Python 解释器检测到错误,触发异常(也允许程序员自己触发异常)。
异常处理
程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)。
如果捕捉成功则进入另外一个处理分支,执行为其定制的逻辑,使程序不会崩溃,这就是异常处理。
用处
程序开发时,很难将所有的特殊情况都处理的面面俱到,通过异常捕获可以针对突发事件做集中的处理,从而保证程序的稳定性和健壮性。
当 Python 解释器抛出异常时,最后一行错误信息的第一个单词,就是错误类型。
1、捕获异常
格式一
try … except …
# 例一
try:
print(a)
except:
print('出现错误')
# 运行结果:
# 出现错误
# 例二
try:
a
except IndexError as e:
print(e)
# 运行结果:
# NameError: name 'a' is not defined
# 例三
try:
a
except Exception as e: # 万能异常:Exception 可以捕获任意异常
print(e)
# 运行结果:
# name 'a' is not defined
如果想要的效果是,无论出现什么异常,统一丢弃,或者使用同一段代码逻辑去处理它们,那么只有一个 Exception 就足够了。
如果想要的效果是,对于不同的异常需要定制不同的处理逻辑,那就需要用到多分支了。
# 多分支
try:
a
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except NameError as e:
print(e)
# 运行结果:
# name 'a' is not defined
格式二
try … except … else
在 if 中,else 的作用是当条件不满足时执行的实行。
try … except … else 中也是如此,即如果没有捕获到异常,那么就执行 else 中的事情。
else 只有在没有异常时才会执行的代码。
try:
a = 1
print(a)
except NameError:
print('出现错误')
else:
print('没有捕获到异常')
# 运行结果:
# 1
# 没有捕获到异常
格式三
try … except … finally …
finally 无论是否有异常,都会执行的代码。
在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用 finally。
比如文件关闭,释放锁,把数据库连接返还给连接池等。
try:
print(a)
except NameError:
print('出现错误')
finally:
print('哈哈哈')
# 运行结果:
# 出现错误
# 哈哈哈
2、完整捕获异常
try:
n = int(input('请输入整数:')) # 尝试执行的代码
print(8/n)
except ValueError:
print('请输入正确的数据') # 针对错误类型1,对应的代码处理
except ZeroDivisionError: # 针对错误类型2,对应的代码处理
print('除0错误')
except Exception as e:
print('未知错误 %s' % e)
else:
print('没有异常才会执行的代码')
finally:
print('无论是否有异常,都会执行的代码')
# 运行结果:
# 请输入整数:qw
# 请输入正确的数据
# 无论是否有异常,都会执行的代码
3、异常的传递
从产生异常的地方开始传递到调用异常的地方,如果一直没有处理异常,会一直传递到主函数,然后停止,程序并报出异常信息。
1、在开发中,可以在主函数中增加异常捕获。
2、而在主函数中调用的其它函数,只要出现异常,都会传递到主函数的异常捕获中。
3、这样就不需要在代码中,增加大量的异常捕获,能够保证代码的整洁。
# 例一:
def funa():
return int(input('请输入整数:'))
def funb():
return funa()
try:
print(funb())
except Exception as e:
print('错误: %s'%e)
# 运行结果:
# 请输入整数:qw
# 错误: invalid literal for int() with base 10: 'qw'
# 例二:
def test():
num = int(input('请输入:'))
return 10 / num
def test2():
print(test())
try:
test2()
except ValueError:
print('类型错误,输入不正确')
except ZeroDivisionError:
print('非零')
else:
print('运行成功')
finally:
print('最后执行')
# 运行结果:
# 请输入:qw
# 类型错误,输入不正确
# 最后执行
4、抛出异常
Python 中提供了一个 Exception 异常类。
应用场景:
在开发中,除了代码执行出错 Python 解释器会抛出异常之外,
还可以根据应用程序特有的业务需求主动抛出异常
主动抛出异常分两步:
1、创建一个 Exception(‘XXX’) 的对象, XXX 为异常提示信息。
2、raise 抛出这个对象(异常对象)。
# 例一:
def funa():
raise Exception('抛出一个异常') # 异常被抛出,print 函数无法执行
print('啊哈哈')
funa()
# 运行结果:
# Traceback (most recent call last):
# File "F:\Python\pythonProject\main.py", line 6, in <module>
# funa()
# File "F:\Python\pythonProject\main.py", line 3, in funa
# raise Exception('抛出一个异常') #异常被抛出,print函数无法执行
# Exception: 抛出一个异常
# 例二:
def funa():
pwd = input('请输入密码:')
if len(pwd) >=6: # 判断密码长度
return pwd
# 创建异常对象 - 使用异常的错误信息字符串作为参数
ex = Exception('长度不够')
raise ex # 抛出异常对象
try:
upwd= funa()
print(upwd)
except Exception as e:
print('错误:%s'%e)
使用 try … except 的方式
1、把错误处理和真正的工作分开来
2、代码更易组织,更清晰,复杂的工作任务更容易实现
3、毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了
try … except 应该尽量少用,因为它本身就是附加程序的一种异常处理的逻辑,与主要的工作是没有关系的。
这种东西加的多了,会导致代码可读性变差,只有在有些异常无法预知的情况下,才应该加上 try … except,其它的逻辑错误应该尽量修正。
记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~