【Python】后悔没早点知道 Python 异常的这 9 个事

1)异常层次

Python 有许多内置异常,我们可能时不时会遇到,例如ZeroDivisionError、KeyError、ValueError、TypeError等等。

每个异常都是异常层次结构的一部分 -- 这意味着大多数异常都以某种方式从同一个父类Exception继承。

我们可以通过._subclasses_()打印某些异常类的子类来查看这一点。

f2362dbb0e0f06497ac209e7e7be27aa.jpeg

另一种方法是使用.__bases__检查异常的父类

7ca30e31f763a8a7871d0babdc24bc7c.jpeg

这可能很麻烦,所以我创建了一个函数来帮助你自动执行此操作:

ea3c0a3bef9421e59935ecb641f1f911.png

一些例子:

9694e980a6a58c5e92d48bb82ad3bbc6.png 1f5333ab31f2107dd525676e3fa6c26a.png

2)BaseException 与 Exception

上面我们看到了ExceptionBaseException 并且Exception继承自其父类BaseException

那么有什么区别呢?

  • Exception是我们在常规编码中遇到的最常见异常的父类,例如ZeroDivision、ValueError、TypeError、KeyError

  • BaseException用来和Exception区别,其他继承自BaseException的异常一般用于特殊情况

  • BaseException的一些子类包括KeyboardInterrupt,SystemExit等

cc73ddeffdf32ee3494184a00193c1a1.png

当我们创建自定义异常时,我们几乎应该从Exception而不是 BaseException 继承,因为Exception意味着它是由于常规编码错误或问题导致的正常错误。

另一方面,BaseException包含其他特殊异常,如KeyboardInterruptSystemExit,当我们想要退出 Python 程序时会强制引发这些异常。

假设我们有一个写得很糟糕的 while 循环,要求用户输入:

f3ff37f8ce0284954698cf320927bff0.png

如果我们希望退出这个 while 循环,我们可以按 Control-C 来强制KeyboardInterrupt结束我们的 Python 程序。

但是如果我们将 BaseException 作为 e 除外,就会发生一些奇怪的事情。

e2057178723d8bbf402f02c022362c15.png

我们现在无法使用 Control-C 强制KeyboardInterrupt结束我们的程序——我们现在只能终止整个终端实例。

重要的是——排除 BaseException 是不好的做法,因为这可能会导致程序出现奇怪的副作用。

3)“except Exception as e”应该放在最后

假设每个 try 块有多个异常,并且每个异常块以某种方式处理不同的异常。

729b2235c99b5a5d06d89666b8e668b1.png

由于排序的原因,我们首先检查是否存在 ZeroDivisionError

  • 如果有,则执行该except块。

  • 如果没有,我们继续下一个区块

  • except Exception as e块捕获了之前未捕获的所有其他异常,因此它应该是最后一个

如果我们把except Exception 作为 e 放在第一位,它会处理所有异常,而其他except块将不会执行。

ccfc1afe471654df7796a4fbe00d2804.png

注意 — ZeroDivisionError是 Exception 的子类这就是为什么我们需要将它放在except Exception as e块之前。

4) except (Exception1, Exception2) as e

但是如果我们想以相同的方式处理一堆异常怎么办?我们是否必须为每个异常重复代码?例如:

a6faf689a254904afade98c45aace57d.png

我们不必重复那么多代码。

在上面的例子中,以相同方式处理异常的前 3 个except块可以这样压缩为一个except块:

f8e43f2a8d115bb3e30edc0a15a9adde.jpeg

这里,第一个except块捕获ZeroDivisionError、ValueErrorKeyError,并以相同的方式处理它们。

5)用消息断言

我们通常使用assert关键字来检查某个条件是否满足。

  • 如果条件为 True,则不发生任何事情

  • 如果条件为 False,则发生 AssertionError

ffad472fcf9ace8c5336130ab3731661.png

这是一个简单的功能示例——我们要求用户输入,但唯一有效的输入是“A”或“B”。因此,我们使用断言语句来确保这一点。

86d042e8890d5f6dfa0e4c7f80abc3ea.png

如果我们输入除 A 或 B 之外的任何内容,我们都会得到 AssertionError:

ef219979f0e4820d2d9a7e378b99fd22.jpeg

但是你知道我们可以向 AssertionError 添加自定义消息吗?我们只需要在断言消息后面添加一个字符串(以逗号分隔)

b07bdb849e6bcb86ffe30b3428fe4f1d.png

当发生 AssertionError 时,还会显示断言消息。

4a210d28d34c94513585cb39e6bbc9ca.jpeg

6)如何忽略断言语句

有一种方法可以忽略所有现有的assert语句。那就是在运行 Python 脚本时使用 -O 标志。

假设我们有以下带有assert语句的 Python 脚本。我们使用命令python filename.py正常运行它

c8a494bf48be00eb06d5a1c1ef7dde00.png

这里,我们只是得到一个 AssertionError 并且根本没有到达我们的打印语句。

但是,我们可以使用 -O 标志忽略assert语句。我们现在使用命令python -O filename.py运行此脚本

8330f3da794070296ab8ebe15dd5c771.png

注意——这是大写的 O

当我们使用 -O 标志运行 Python 时,特殊变量*debug*变为 False(默认情况下通常为 True)。因此,所有assert语句都会被忽略。

如果我们有许多assert语句,但希望运行所有代码而没有任何assert语句触发 AssertionError,那么这个技巧很有用。

7)try except else 块

我们可能在学习 Python 基础知识时已经学习过 try-except-finally 块。但是您听说过 try-except-else-finally 块吗?

9760679f5f566957e5b1dc6002553f14.png

else块位于except块之后。

  • 如果发生异常,则except块运行,但else块不运行

  • 如果没有发生异常,则except块不会运行,但else块会运行。

我们强制执行 ZeroDivisionError。在这种情况下,由于except块运行,所以else块不会运行。无论如何, finally块始终会运行。

5e75dfeeda181bff34399e541fc10a5f.png

现在让我们让try块无错误地运行。现在没有发生任何异常,我们的except块不会运行。因此,我们的else块会运行。

be91f363ec8a806388e80d1b70a43a62.png

8)finally 块可以在 return 语句之后运行

正常情况下,函数中return语句之后不会发生任何事情。一旦执行return语句,我们就会立即退出函数。

编写一个简单的函数来说明这一点:

2f9368caf2cacd30bce9da025533cca1.png

这里,print('orange')没有运行,因为它发生在return语句之后。return语句运行后,我们的函数立即停止,并忽略之后发生的一切。

但使用try-except-finally 中的 finally块,我们可以绕过这个限制?

无论如何,finally块内的代码都会运行。即使在函数内的return语句之后也是如此。

7c47107aa30474c398220acf11380685.png

这里,我们在 try 块中 print('apple') 并返回 1。但是即使在执行 return 语句之后,我们仍然会像在 finally 块中一样 print('orange')。

如果我们有无论如何都需要运行的代码,这很有用,例如关闭文件或关闭数据库连接(否则可能会导致内存泄漏和其他问题)

9)raise Exception1 from Exception2

在更复杂的应用程序中,我们可能希望引发一系列异常,而不是单个异常。这样,我们就能更好地追踪异常的确切来源和原因。

为此,我们可以使用语法raise Exception1 from Exception2。

下面是一个简单的例子:

c9980b161e1df8188e876f3694457718.png

这里,我们首先强制引发 ZeroDivisionError。

在我们的except块中,我们从之前引发的 ZeroDivisionError 中引发另一个 ValueError。这样,我们得到了由 ZeroDivisionError 引起的 ValueError。

为了查找和检查异常的原因,我们可以简单地使用.__cause__属性。

 
 

8bbdc774e716eaccecefec6ae2cf13e6.jpeg

 
 
 
 
 
 
 
 
 
 
往期精彩回顾




适合初学者入门人工智能的路线及资料下载(图文+视频)机器学习入门系列下载机器学习及深度学习笔记等资料打印《统计学习方法》的代码复现专辑
  • 交流群

欢迎加入机器学习爱好者微信群一起和同行交流,目前有机器学习交流群、博士群、博士申报交流、CV、NLP等微信群,请扫描下面的微信号加群,备注:”昵称-学校/公司-研究方向“,例如:”张小明-浙大-CV“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~(也可以加入机器学习交流qq群772479961)

626af8bd97a5516392487064dd55ec9f.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值