Python异常处理,Python异常,在使用 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
。块中的第一个 print 语句try
抛出TypeError
异常。Python 解释器检查每个except
子句以找到合适的异常类,该异常类由第二个except
块处理。“无法连接字符串和整数”打印在控制台中。
块中的第二个打印语句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
密码是否满足要求的长度,如果不满足条件则引发指定的异常。Stack OverFlow检查了为什么可以引发异常而不是仅仅打印到控制台:
引发错误会在此时停止整个程序(除非异常被捕获),而打印消息只是写入一些东西——输出
stdout
可能会通过管道传输到另一个工具,或者有人可能没有从命令行运行你的应用程序,并且可能永远看不到打印输出。引发异常,将该条件的处理委托给调用堆栈更上层的东西。
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
在上面的示例中,我们试图读取子句robots.txt
中的文件。try
由于没有引发异常,因此else
执行子句中的代码。else
子句中出现异常,因为x
在变量中找不到子字符串upper_case
。当没有 except 子句来处理异常时——如上面的代码片段所示——finally
首先执行该子句,然后重新引发异常。
Python 文档是这样解释的:
except
在执行or子句期间可能会发生异常else
。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
则会引发 a。该except
子句将处理异常,然后finally
执行该子句中的打印语句。
结论
在本教程中,我们了解了语法错误和异常之间的主要区别。我们还看到语法错误或异常会破坏我们程序的正常流程。
我们还了解到try
和except
语句是 Python 中处理异常的标准语法。
在构建实际应用程序时异常处理很重要,因为您希望检测错误并适当地处理它们。Python 提供了一长串内置异常,这些异常在处理异常时非常有用。
相关