Python异常处理详解:概念、语法与实践

1. 异常的概念

在Python中,异常(Exception)是程序运行时出现的错误或不正常情况。异常通常表示程序在运行时遇到了无法继续执行的条件。Python通过 try/except 语句来捕获和处理异常。

异常可以分为两类:

  • 内建异常:Python提供了一些内建的异常类,表示常见的错误情况,比如 IndexErrorTypeErrorValueError 等。
  • 自定义异常:开发者可以自定义异常类型来表示特定的错误或问题。

2. 常见的内建异常

Python中有很多内建异常类,每种异常类表示不同的错误类型。以下是一些常见的内建异常:

  • SyntaxError:语法错误,表示代码语法不正确。
  • TypeError:类型错误,表示操作或函数应用于错误类型的对象。
  • ValueError:值错误,表示传递给函数的参数的值不合适。
  • IndexError:索引错误,表示访问的索引超出了范围。
  • KeyError:键错误,表示在字典中访问一个不存在的键。
  • AttributeError:属性错误,表示访问对象不存在的属性。
  • ZeroDivisionError:除零错误,表示除法操作中的除数为零。
  • FileNotFoundError:文件未找到错误,表示操作文件时找不到指定的文件。
  • Exception:所有异常的基类,捕获其它未处理的异常时,通常使用 Exception

3. 异常处理的基本语法

Python使用 tryexcept 块来捕获和处理异常:

try:
    # 可能会引发异常的代码
    result = 10 / 0
except ZeroDivisionError as e:
    # 处理异常的代码
    print(f"错误: {e}")
  • try:用于包裹可能引发异常的代码块。
  • except:用于捕获和处理异常。如果 try 代码块中的某些代码引发了异常,程序会跳转到相应的 except 块执行。
  • as:用于给捕获到的异常实例命名,可以在 except 块中使用该实例进行进一步处理。

4. 多个异常的处理

你可以在同一个 try 块中捕获多种不同类型的异常:

try:
    x = int(input("请输入一个数字: "))
    result = 10 / x
except ValueError:
    print("输入的不是有效的数字")
except ZeroDivisionError:
    print("不能除以零")
except Exception as e:
    print(f"发生了其他错误: {e}")
  • try 代码块中,如果出现多个异常,它们会按照 except 块的顺序进行匹配。
  • 如果异常不在匹配的范围内,会触发 Exception 类捕获,Exception可以捕获所有异常,因为所有的异常都是Exception的子类。 

5. elsefinally

Python的异常处理语句还支持 elsefinally 代码块:

  • else:如果 try 代码块没有引发任何异常,else 代码块会被执行。
  • finally:无论是否发生异常,finally 代码块中的内容都会被执行,通常用于清理资源,如关闭文件或数据库连接。
try:
    result = 10 / 2
except ZeroDivisionError:
    print("不能除以零")
else:
    print("计算成功,结果是:", result)
finally:
    print("清理操作,始终执行")
  • else 语句块中的代码只有在 try 代码块没有引发异常时才会执行。
  • finally 语句块中的代码无论如何都会执行,适合进行资源的释放、日志记录等操作。

6. 抛出异常(raise

除捕获异常,Python还允许你显式地抛出异常。你可以使用 raise 语句来抛出异常,并且可以选择抛出特定类型的异常:了

def check_age(age):
    if age < 0:
        raise ValueError("年龄不能为负")
    return age

try:
    check_age(-5)
except ValueError as e:
    print(e)
  • raise 语句用于抛出异常。你可以在抛出异常时传递一个错误消息(如 ValueError("年龄不能为负")),并且可以自定义错误类型。在except语句中可以直接使用raise重新抛出该异常,让上一层函数处理。
    def function(value):
        try:
            return int(value)  # 尝试将值转换为整数
        except ValueError as e:
            # 如果发生 ValueError 异常,执行此处
            print(f"function_c: 捕获到 ValueError: {e}")
            raise  # 重新抛出异常,以便向上传递
  • 你还可以抛出现有的异常类,也可以自定义异常类。

7. 自定义异常

你可以创建自己的异常类,继承自 Exception 类,来表示特定的错误类型。通常情况下,异常类会有一个 __init__ 方法来接收错误信息或其他有用的参数。

class MyCustomError(Exception):
    """自定义异常类"""
    def __init__(self, message, code):
        super().__init__(message)
        self.code = code

def my_function(value):
    if value < 0:
        raise MyCustomError("值不能为负数!", 1001)

try:
    my_function(-10)
except MyCustomError as e:
    print(f"捕获到自定义异常:{e}, 错误代码:{e.code}")

8. ExceptionGroup(Python 3.11 及之后)

Python 3.11 引入了 ExceptionGroup,这是一个新的异常类型,允许你将多个异常组合在一起。在处理并发任务或多任务环境时,多个异常可能同时发生,此时可以将这些异常组织到ExceptionGroup 中,便于统一处理。

def f():
    raise ExceptionGroup(
        "Multiple errors occurred",
        [ValueError("Invalid value"), KeyError("Missing key")],
    )

try:
    f()
except ExceptionGroup as e:
    print(f"捕获到异常组: {e}")

9. 异常的传递

异常的传播遵循以下过程:

  1. 异常抛出:当程序执行过程中发生错误时,Python 会抛出一个异常。例如,试图将一个字符串转换为整数时,Python 会抛出 ValueError
  2. 异常传播:抛出的异常会沿着调用栈(即函数调用的路径)传播,寻找合适的 except 块来捕获它。如果当前函数没有捕获该异常,异常会继续向上传递到调用该函数的地方。
  3. 捕获异常:一旦异常找到合适的 except 块,程序就会跳转到这个 except 块,执行其中的处理代码。异常传递过程会停止,程序还能正常继续运行剩余内容。
  4. 未捕获异常:如果异常没有在任何 except 块中被捕获,它会继续向上传递,直到程序的顶层。如果在顶层没有合适的异常处理代码,程序会终止并显示异常信息。

例子: 

--- 测试用例 1:正常情况 ---
function_b: function_c 返回结果: 123
function_a: function_b 返回结果: 246

--- 测试用例 2:function_c 抛出 ValueError,function_b 捕获并处理 ---
function_c: 捕获到 ValueError: invalid literal for int() with base 10: 'abc'
function_b: 捕获到 ValueError: invalid literal for int() with base 10: 'abc',进行特殊处理
function_a: function_b 返回结果: -1

--- 测试用例 3:function_c 抛出 ValueError,function_b 没有捕获,function_a 捕获 ---
function_c: 捕获到 ValueError: invalid literal for int() with base 10: 'xyz'
function_a_catch_all: 捕获到其他异常:ValueError invalid literal for int() with base 10: 'xyz'

--- 测试用例 4:function_c 抛出 ValueError,所有函数都没有捕获 ---
function_c: 捕获到 ValueError: invalid literal for int() with base 10: 'error'
Traceback (most recent call last):
  File "g:\python_tutorial-master\progarm\ex.py", line 63, in <module>
Traceback (most recent call last):
  File "g:\python_tutorial-master\progarm\ex.py", line 63, in <module>
  File "g:\python_tutorial-master\progarm\ex.py", line 63, in <module>
    function_a_no_catch("error") # ValueError 没有被捕获,程序终止
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    function_a_no_catch("error") # ValueError 没有被捕获,程序终止
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 60, in function_a_no_catch
    final_result = function_b_no_catch_2(item)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 57, in function_b_no_catch_2
    return function_c(data)
           ^^^^^^^^^^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 7, in function_c
    raise e  # 重新抛出异常,让上一层函数处理
    ^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 4, in function_c
    return int(value)
           ^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'error'


测试用例1:正常情况

--- 测试用例 1:正常情况 ---
function_b: function_c 返回结果: 123
function_a: function_b 返回结果: 246

function_c 成功将 "123" 转换为整数,结果逐层返回,没有异常发生。

测试用例 2:function_c 抛出 ValueError,function_b 捕获并处理

--- 测试用例 2:function_c 抛出 ValueError,function_b 捕获并处理 ---
function_c: 捕获到 ValueError: invalid literal for int() with base 10: 'abc'
function_b: 捕获到 ValueError: invalid literal for int() with base 10: 'abc',进行特殊处理
function_a: function_b 返回结果: -1

function_c 无法将 "abc" 转换为整数,抛出 ValueErrorfunction_b 捕获了这个异常,进行了特殊处理(返回 -1),异常传播停止。

测试用例 3:function_c 抛出 ValueError,function_b 没有捕获,function_a 捕获

--- 测试用例 3:function_c 抛出 ValueError,function_b 没有捕获,function_a 捕获 ---
function_c: 捕获到 ValueError: invalid literal for int() with base 10: 'xyz'
function_a_catch_all: 捕获到其他异常:ValueError invalid literal for int() with base 10: 'xyz'

function_c 抛出 ValueErrorfunction_b_no_catch 没有捕获,异常继续向上传播到 function_a_catch_all,由于function_a_catch_all 使用了except Exception 捕获了所有类型的异常,所以异常在这里被处理了。

测试用例 4:function_c 抛出 ValueError,所有函数都没有捕获

--- 测试用例 4:function_c 抛出 ValueError,所有函数都没有捕获 ---
function_c: 捕获到 ValueError: invalid literal for int() with base 10: 'error'
Traceback (most recent call last):
  File "g:\python_tutorial-master\progarm\ex.py", line 63, in <module>
Traceback (most recent call last):
  File "g:\python_tutorial-master\progarm\ex.py", line 63, in <module>
  File "g:\python_tutorial-master\progarm\ex.py", line 63, in <module>
    function_a_no_catch("error") # ValueError 没有被捕获,程序终止
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    function_a_no_catch("error") # ValueError 没有被捕获,程序终止
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 60, in function_a_no_catch
    final_result = function_b_no_catch_2(item)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 57, in function_b_no_catch_2
    return function_c(data)
           ^^^^^^^^^^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 7, in function_c
    raise e  # 重新抛出异常,让上一层函数处理
    ^^^^^^^
  File "g:\python_tutorial-master\progarm\ex.py", line 4, in function_c
    return int(value)
           ^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'error'

function_c 抛出 ValueError,所有函数都没有捕获,异常最终传播到程序顶层,导致程序终止并打印错误信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值