Self-study Python Fish-C Note17 P57to58

异常 (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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值