社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

数据STUDIO • 6 月前 • 428 次点击  


1)异常层次

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

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

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

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

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

一些例子:

2)BaseException 与 Exception

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

那么有什么区别呢?

  • Exception是我们在常规编码中遇到的最常见异常的父类,例如ZeroDivision、ValueError、TypeError、KeyError
  • BaseException用来和Exception区别,其他继承自BaseException的异常一般用于特殊情况
  • BaseException的一些子类包括KeyboardInterrupt,SystemExit等

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

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

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

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

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

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

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

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

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

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

  • 如果有,则执行该except块。
  • 如果没有,我们继续下一个区块
  • except Exception as e块捕获了之前未捕获的所有其他异常,因此它应该是最后一个

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

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

4) except (Exception1, Exception2) as e

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

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

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

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

5)用消息断言

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

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

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

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

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

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

6)如何忽略断言语句

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

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

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

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

注意——这是大写的 O

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

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

7)try except else 块

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

else块位于except块之后。

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

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

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

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

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

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

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

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

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

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

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

9)raise Exception1 from Exception2

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

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

下面是一个简单的例子:

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

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

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


🏴‍☠️宝藏级🏴‍☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉 PythonMySQL数据分析数据可视化机器学习与数据挖掘爬虫 等,从入门到进阶!

长按👇关注- 数据STUDIO -设为星标,干货速递

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/174479
 
428 次点击