Python 异常处理指北
Posted crazy_itman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 异常处理指北相关的知识,希望对你有一定的参考价值。
自 2003 年以来,Python 一直位列TIOBE 编程社区指数中最受欢迎的十大编程语言之列,截至 2022 年 12 月,它是最受欢迎的语言(领先于 C、C++ 和Java)。它在 2007 年、2010 年、2018 年和 2020 年被选为年度编程语言(因为“一年中收视率上升最快”)(截至 2020 年,唯一一种四次获得此殊荣的语言) .一项实证研究发现,对于涉及字符串操作和字典搜索的编程问题,脚本语言(如 Python)比传统语言(如 C 和 Java)效率更高,并确定内存消耗通常“优于 Java 而不是比 C 或 C++ 差得多”。使用 Python 的大型组织包括维基百科、谷歌、雅虎!, CERN, NASA, Facebook, Amazon,Instagram, Spotify,和一些较小的实体,如ILM 和ITA。社交新闻网站Reddit主要是用 Python 编写的。
在使用 Python 编程时,通常会遇到两种类型的错误:语法错误和异常。
任何由无效语法、缩进或编程结构导致的错误通常被视为语法错误。当出现语法错误时,程序会在语法错误发生的地方崩溃。
异常是破坏计算机程序正常流程的异常情况。当异常发生时,我们应该处理这些异常以确保我们的程序不会突然崩溃。
异常处理是在计算机程序中实施检查以处理在我们的程序执行期间可能发生的错误(无论是否预期)的过程。(与大多数其他语言相比,Python 更倾向于“做事并请求原谅”的编程风格)
异常处理
与其他所有编程语言一样,Python 有一种处理程序执行期间发生的异常的方法。这意味着异常得到妥善处理:我们的 Python 程序不会崩溃。当语法正确的程序在运行时发生错误时,Python 使用try
语句和except
子句来捕获和处理异常。
由于大多数异常都是预期的,因此有必要在我们的 Python 程序中更有针对性或更具体地处理异常。特定的异常处理使程序的调试更加容易。
一些标准的 Python 异常
Python 有一个内置的异常列表,用于处理不同的异常。下面是一些内置的 Python 异常。
序列号 | 异常名称 | 描述 |
---|---|---|
1 | Exception | 所有用户定义的异常也应该从此类派生。 |
2 | ArithmeticError | 为各种算术错误引发的那些内置异常的基类。 |
3 | BufferError | 当无法执行缓冲区相关操作时引发。 |
4 | LookupError | 当用于映射或序列的键或索引无效时引发的异常的基类。 |
5 | AssertionError | 当断言语句失败时引发。 |
6 | AttributeError | 当属性引用或赋值失败时引发。 |
7 | ImportError | 当 import 语句在尝试加载模块时遇到问题时引发。 |
8 | IndexError | 当序列下标超出范围时引发。 |
9 | KeyError | 在现有键集中找不到映射(字典)键时引发。 |
10 | NameError | 当找不到本地或全局名称时引发。 |
11 | OverflowError | 当算术运算的结果太大而无法表示时引发。 |
12 | RuntimeError | 当检测到不属于任何其他类别的错误时引发。 |
13 | StopIteration | 由内置函数next() 和迭代器的__next__() 方法引发,以发出迭代器不再生成任何项的信号。 |
14 | SyntaxError | 当解析器遇到语法错误时引发。 |
15 | TypeError | 当操作或功能应用于不适当类型的对象时引发。 |
16 | ValueError | 当操作或函数接收到具有正确类型但值不合适的参数时引发。 |
17 | ZeroDivisionError | 当除法或模运算的第二个参数为零时引发。 |
18 | FileExistsError | 尝试创建已存在的文件或目录时引发。 |
19 | FileNotFoundError | 当请求文件或目录但不存在时引发。 |
使用 try 和 except 语句处理 Python 异常
try
和except
块用于 Python 中的异常处理。语法如下所示:
try:
# some code that could cause an exception
except:
# some code to execute to handle exception
该try
块包含一段可以引发异常的代码,而该except
块包含一些处理异常的代码。
下面我们举一个简单的例子:
print(3/0)
上面的代码将在程序终止时生成一条错误消息:
Traceback (most recent call last):
File "/home/ini/Dev/Tutorial/sitepoint/exception.py", line 53, in <module>
print(3/0)
ZeroDivisionError: division by zero
抛出异常的代码行可以这样处理:
try:
print(3/0)
except ZeroDivisionError:
print("Cannot divide number by Zero")
在上面的示例中,我们将第一个打印语句放在try
块中。此块中的代码片段将引发异常,因为将数字除以零没有任何意义。该except
块将捕获try
块中引发的异常。try
和except
块通常一起用于处理 Python 中的异常。我们只是在控制台中打印了“Cannot divide number by Zero”,而不是之前生成的错误消息。
多个 Python 例外
在 Python中,有时会使用两个或多个except
块来捕获不同的异常。多个 except 块帮助我们捕获特定的异常并在我们的程序中以不同的方式处理它们:
try:
number = 'one'
print(number + 1)
print(block)
except NameError:
print("Name is undefined here")
except TypeError:
print("Can't concatenate string and int")
这是上面代码的输出:
Can't concatenate string and int
从上面的示例中,我们有两个except
块指定我们要处理的异常类型:NameError
和TypeError
。try
块中的第一个 print 语句抛出TypeError
异常。Python 解释器检查每个except
子句以找到合适的异常类,该异常类由第二个except
块处理。“Can't concatenate string and int”打印在控制台中。
try
块中的第二个打印语句被跳过,因为发生了异常。但是将执行最后一个except
子句之后的任何代码:
try:
number = 'one'
print(number + 1)
print(block)
except NameError:
print("Name is undefined here")
except TypeError:
print("Can't concatenate string and int")
for name in ['Chris', 'Kwame', 'Adwoa', 'Bolaji']:
print(name, end=" ")
这是上面代码的输出:
Can't concatenate string and int
Chris Kwame Adwoa Bolaji
因为已经处理了异常,所以会执行try和except块之后的for
循环。
一个通用的 Python except
我们可以有一个通用except
块来捕获 Python 中的所有异常。通用except
块可以与我们程序中的其他特定except
块一起使用,以捕获未处理的异常。在所有特定块之后放置最通用的except
子句是合乎逻辑的。这将在发生未处理的except
异常时启动。我们用最后一个通用except
块修改我们之前的示例:
names = ['Chris', 'Kwame', 'Adwoa', 'Bolaji']
try:
print(names[6])
number = 'one'
print(number + 1)
print(block)
except NameError:
print("Name is undefined here")
except TypeError:
print("Can't concatenate string and int")
except:
print('Sorry an error occured somewhere!')
for name in names:
print(name, end=" ")
这是上面代码的输出:
Sorry an error occured somewhere!
Chris Kwame Adwoa Bolaji
但是出现IndexError
异常,因为它没有在任何指定的except
块中处理。通用的except
块处理了异常。执行通用块中的语句并执行for
之后的循环,并在控制台中打印相应的输出。
raise语句
有时在我们的 Python 程序中,我们可能希望在某些不符合我们要求的条件下使用raise
关键字引发异常。该raise
语句由关键字本身、一个异常实例和一个可选参数组成。让我们看下面的代码片段:
def validate_password(password):
if len(password) < 8:
raise ValueError("Password characters less than 8")
return password
try:
user_password = input('Enter a password: ')
validate_password(user_password)
except ValueError:
print('Password should have more characters')
检查密码是否满足要求的raise ValueError
长度,如果不满足条件则引发指定的异常。
else 子句
else
子句可以添加到标准try
和except
块中。它位于except
子句之后。该else
子句包含我们希望在try
语句未引发异常时执行的代码。让我们考虑以下代码:
try:
number = int(input('Enter a number: '))
if number % 2 != 0:
raise ValueError
except ValueError:
print("Number must be even")
else:
square = number ** 2
print(square)
当用户输入偶数时,我们的代码运行时不会引发异常。然后该else
子句执行。我们现在在控制台中打印了偶数的平方。但是,else
子句中可能出现的异常不会由前面的except
块处理。
finally 子句
finally
子句可以添加到try
和except
块中,并应在必要时使用。finally
无论是否发生异常,子句中的代码始终执行。请参阅下面的代码片段:
try:
with open('robots.txt', 'r', encoding='UTF-8') as f:
first_line = f.readline()
except IOError:
print('File not found!')
else:
upper_case = first_line.upper()
print(upper_case.index('x'))
finally:
print('The Python program ends here!')
这是上面代码的输出:
The Python program ends here!
Traceback (most recent call last):
File "/home/ini/Dev/python/python_projects/extra.py", line 89, in <module>
print(upper_case.index('x'))
ValueError: substring not found
在上面的示例中,我们试图读取try子句中robots.txt
中的文件内容。由于没有引发异常,因此执行else
子句中的代码。else
子句中出现异常,因为x
在变量中找不到子字符串upper_case
。当没有 except 子句来处理异常时——如上面的代码片段所示——finally
首先执行该子句,然后重新引发异常。
Python 文档是这样解释的:
except
在执行orelse
子句期间可能会发生异常。finally
同样,在执行子句后再次引发异常。
异常组
ExceptionGroup
在 Python 3.11 中可用。它提供了一种引发多个不相关异常的方法。处理ExceptionGroup
的首选语法是except*
. 异常组的语法如下所示:
ExceptionGroup(msg, excs)
初始化时,异常组有两个参数,msg
和excs
:
-
msg
: 描述性信息 -
excs
:异常子组序列
让我们创建一个实例ExceptionGroup
:
eg = ExceptionGroup('group one', [NameError("name not defined"), TypeError("type mismatch")])
实例化异常组时,异常子组列表不能为空。我们将触发我们之前创建的异常组的一个实例:
raise eg
这是上面代码的输出:
+ Exception Group Traceback (most recent call last):
| File "<string>", line 10, in <module>
| ExceptionGroup: group one (2 sub-exceptions)
+-+---------------- 1 ----------------
| NameError: name not defined
+---------------- 2 ----------------
| TypeError: type mismatch
+------------------------------------
显示的回溯展示了异常组中包含的所有异常子组。
如前所述,ExceptionGroup
最好用except*
子句处理,因为它可以挑出异常组中的每个特定异常。通用except
子句只会将异常组作为一个单元来处理,而不是具体的某一个。
请参阅下面的代码片段:
try:
raise ExceptionGroup('exception group', [NameError("name not defined"), TypeError("type mismatch"), ValueError("invalid input")])
except* NameError as e:
print("NameError handled here.")
except* TypeError as e:
print("TypeError handled here.")
except* ValueError:
print("ValueError handled here.")
这是该代码的输出:
NameError handled here.
TypeError handled here.
ValueError handled here.
每个except*
子句处理异常组中的目标异常子组。任何未处理的子组都将重新引发异常。
Python 中的用户定义异常
内置异常很好,但我们的软件项目可能需要自定义异常。Python 允许我们创建用户定义的异常以满足我们的需要。Python 文档指出:
所有异常都必须是派生自
BaseException
的类的实例。
自定义异常是通过继承 Python的Exception
类派生的。自定义异常的语法如下所示:
class CustomExceptionName(Exception):
pass
try:
pass
except CustomExceptionName:
pass
让我们创建一个自定义异常并在以下示例的代码中使用它:
class GreaterThanTenError(Exception):
pass
try:
number = int(input("Enter a number: "))
if number > 10:
raise GreaterThanTenError
except GreaterThanTenError:
print("Input greater than 10")
else:
for i in range(number):
print(i ** 2, end=" ")
finally:
print()
print("The Python program ends here")
在上面的示例中,我们创建了自己的类,其异常名称为GreaterThanTenException
,它继承自Exception
超类。我们在其中放置了一些可能会在try
块中引发异常的代码,except
块是我们的异常处理程序。如果没有抛出异常,则该else
子句具有要执行的代码。最后,finally
无论结果如何,该语句都会执行。
如果我们的 Python 程序的用户输入一个大于 10 的数字,则会引发 一个GreaterThanTenError
错误,该except
子句将处理异常,然后finally
执行该子句中的打印语句。
结论
在本文中,我们了解了语法错误和异常之间的主要区别。我们还看到语法错误或异常会破坏我们程序的正常流程。
我们还了解到try
andexcept
语句是 Python 中处理异常的标准语法。
在构建实际应用程序时异常处理很重要,因为您希望检测错误并适当地处理它们。Python 提供了一长串内置异常,这些异常在处理异常时非常有用。
以上是关于Python 异常处理指北的主要内容,如果未能解决你的问题,请参考以下文章