异常 (exception)
在我们的代码出错无法正常运行的时候,python就会给我们报异常,比如没有按照python的语法规则:
print(sfs')
这里就报了一个 SyntaxError
的异常:
print(sfs')
^
SyntaxError: EOL while scanning string literal
再比如常见的,除数是0:
1/0
会报 ZeroDivisionError
的异常
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\2354412189.py in <module>
----> 1 1/0
ZeroDivisionError: division by zero
再比如:
'abc'+123
异常:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\1150065593.py in <module>
----> 1 'abc'+123
TypeError: can only concatenate str (not "int") to str
事实上,python有内置的很多种异常的类别,可以参考官方文档的内置异常的总结:https://docs.python.org/zh-cn/3.12/library/exceptions.html
处理异常
try - except
语句
在代码中捕获并处理异常的方法,使用 try - except
语句。
语法:
try:
检测范围
except [expression [as identifier]]:
异常处理代码
示例:
try:
1/0
except:
print('something wrong')
# 我们将 1/0 这个操作放在了 try 语句的检测范围内,所以引发异常后的操作是去执行 except 语句的异常处理代码,而不是直接抛出红色的输出
something wrong
如果 try
语句没有检测到异常,那么 except
语句的代码就不会被执行
try:
print(1/1)
except:
print('something wrong')
1.0
我们还可以在 except
后面指定一个具体的异常类型。 这样只有当捕获到的异常是指定的具体异常的时候,才会执行 except
语句的内容,否则正常报错。
比如:
try:
'abc'+123
except ZeroDivisionError:
print('something wrong')
依然会报错:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\3347852249.py in <module>
1 try:
----> 2 'abc'+123
3 except ZeroDivisionError:
4 print('something wrong')
TypeError: can only concatenate str (not "int") to str
我们还可以在指定具体异常后面加上一个可选的 as
,来将异常的原因提取出来:
try:
1/0
except ZeroDivisionError as e:
print(e)
division by zero
我们还可以将多个可能出现的异常使用元组的形式包裹起来:
try:
1/0
520+'fff'
except (ZeroDivisionError, SyntaxError, TypeError):
print('nothing happened')
# 这时候,什么都不会发生,因为捕捉到这些异常中一个就会执行 except 的语句
nothing happened
我们还可以使用多个 except
语句,单独处理不同的异常
但是注意下面的示例,我们可以看到直接打印 do someting 2 而不做任何事情,因为代码捕获到异常,就直接跳到了它指定的异常处理的代码,然后直接往下走了,后面的语句就被跳过了。
try:
1/0
520+'fff'
except SyntaxError:
print('do someting 1')
except ZeroDivisionError:
print('do someting 2')
except TypeError:
print('do someting 3')
do someting 2
try - except - else
语句
当 try
语句里没有检测出任何异常的情况下,那么就会执行 else 语句的内容了
try:
1/0
except:
print('got it')
else:
print('did not get it')
got it
try:
1/1
except:
print('got it')
else:
print('did not get it')
did not get it
try - except - finally
语句
finally
语句的含义是无论异常是否发生,都必须会执行的内容
try:
1/0
except:
print('got it')
else:
print('did not get it')
finally:
print('always run')
got it
always run
finally
语句一般可以执行一些收尾工作,比如关闭一个文件。如下面的列子就可以达到,无论 try
语句中是否存在异常,文件都会被正确的关闭。和 with
上下文管理器一样。
try:
f = open('e1.txt','w')
f.write('aaaaa')
f.writ
except:
print('something wrong')
finally:
f.close()
something wrong
try - finally
语句
try - finally
语句,用法:
try:
while True:
pass
finally:
print('wrong')
我们运行程序以后,发现程序不动了,一直再跑,因为触发了死循环。如果我们 Ctrl+C
停下来。此时,在触发 KeyboardInterrupt
的异常的时候,会先执行 print('wrong')
这一句。
wrong
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\704652187.py in <module>
1 try:
2 while True:
----> 3 pass
4 finally:
5 print('wrong')
KeyboardInterrupt:
所以发生异常与否,都会执行 finally
里的内容。
异常处理的语法总结:
try:
检测范围
except [expression [as identifier]]:
异常处理代码
[except [expression [as identifier]]:
异常处理代码]*
[else:
没有触发异常时执行的代码]
[finally:
收尾工作执行的代码]
或者
try:
检测范围
finally:
收尾工作执行的代码
方括号([]
)包裹的内容代表是可选的,星号(*
)表示可以是0个或者多个
异常的嵌套
异常也是可以被嵌套的,示例:
try:
try:
111+'aaa'
except:
print('inner exception')
1/0
except:
print('outer exception')
finally:
print('something always need to be done')
inner exception
outer exception
something always need to be done
# 如果在内部异常前面发生异常,内部异常就会被跳过
try:
1/0
try:
111+'aaa'
except:
print('inner exception')
except:
print('outer exception')
finally:
print('something always need to be done')
outer exception
something always need to be done
raise
语句
可以直接抛出一个异常
raise ValueError('值不正确')
结果:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\194320206.py in <module>
----> 1 raise ValueError('值不正确')
ValueError: 值不正确
但是注意,我们不能抛出不存在的异常
raise someError('not exist')
会执行不了:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\2649670473.py in <module>
----> 1 raise someError('not exist')
NameError: name 'someError' is not defined
raise
语句,偷换异常类型(实际会抛出警告)
try:
1/0
except:
raise ValueError('This is not correct')
实际抛出警告 During handling of the above exception, another exception occurred:
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\2728416624.py in <module>
1 try:
----> 2 1/0
3 except:
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\2728416624.py in <module>
2 1/0
3 except:
----> 4 raise ValueError('This is not correct')
ValueError: This is not correct
异常链 (raise
+ from
)
raise ValueError('This is not correct') from ZeroDivisionError
异常链,ValueError
是来自于 ZeroDivisionError
这个形式
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
ZeroDivisionError:
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\2938836258.py in <module>
----> 1 raise ValueError('This is not correct') from ZeroDivisionError
ValueError: This is not correct
assert
语句
assert
语句和 raise
类似,都是主动引发异常,不过 assert
语句只能引发一个 AssertionError
的异常。
assert
(断言)用于判断一个表达式,在表达式条件为 false
的时候触发异常。
语法:
assert expression [, arguments]
等价于:
if not expression:
raise AssertionError(arguments)
示例:
s = 1
assert s!=1,'s is 1'
结果:
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_5332\4273234057.py in <module>
1 s = 1
----> 2 assert s!=1,'s is 1'
AssertionError: s is 1
利用异常来实现 goto
(补充内容)
感觉利用价值不大?
示例:
try:
while True:
while True:
for i in range(10):
if i>3:
raise AssertionError('aaaa')
print(i)
print('被跳过')
print('被跳过')
print('被跳过')
except:
print('到这来了')
0
1
2
3
到这来了
附言:
题目:Self-study Python Fish-C Note-17 P57-P58
本文为自学B站上鱼C的python课程随手做的笔记。一些概念和例子我个人为更好的理解做了些查询和补充
因本人水平有限,如有任何问题,欢迎大家批评指正!
原视频链接:https://www.bilibili.com/video/BV1c4411e77t?p=8