Python3 错误和异常

发布时间 2023-12-22 11:57:02作者: 善战者求之于势

一、基础概念

1.1 什么叫做语法错误?

ython 的语法错误或者称之为解析错,是初学者经常碰到的,如下实例

>>> while True print('Hello world')
  File "<stdin>", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

这个例子中,函数 print() 被检查到有错误,是它前面缺少了一个冒号(:)。

语法分析器指出了出错的一行,并且在最先找到的错误的位置标记了一个小小的箭头。

1.2 什么叫做异常?

即便 Python 程序的语法是正确的,在运行它的时候,也有可能发生错误。运行期检测到的错误被称为异常。

1.3 try-except语法

try-except 结构是 Python 中用于异常处理的语法结构,它的一般形式如下:

pythonCopy codetry:
    # 可能引发异常的代码块
    # ...
except ExceptionType1 as variable1:
    # 处理 ExceptionType1 类型的异常
    # ...
except ExceptionType2 as variable2:
    # 处理 ExceptionType2 类型的异常
    # ...
# 可以有多个 except 块处理不同类型的异常
except (ExceptionType3, ExceptionType4) as variable34:
    # 处理 ExceptionType3 或 ExceptionType4 类型的异常
    # ...
else:
    # 如果没有异常发生时执行的代码
    # ...
finally:
    # 无论是否发生异常,都会执行的代码
    # ...

下面是 try-except 结构的主要部分解释:

  • try 块: 包含可能引发异常的代码块。当异常发生时,程序将跳转到适当的 except 块处理异常。
  • except 块: 用于捕获和处理特定类型的异常。每个 except 块可以处理一个或多个异常类型,也可以使用括号将多个异常类型组合在一起。
  • as variable 用于将捕获到的异常赋值给一个变量,以便在 except 块中访问异常对象的信息。
  • else 块: 包含在没有发生异常时执行的代码。它是可选的。
  • finally 块: 包含无论是否发生异常都会执行的代码。它也是可选的。

二、异常关键词解析

2.1 raise 抛出异常

Python 使用 raise 语句抛出一个指定的异常。例如:

>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere

raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。

如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出。

>>> try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise
   
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

2.2 定义清理行为

try 语句还有另外一个可选的子句,它定义了无论在任何情况下都会执行的清理行为。 例如:

>>> try:
        raise KeyboardInterrupt
    finally:
        print('Goodbye, world!')
   
Goodbye, world!
KeyboardInterrupt

以上例子不管 try 子句里面有没有发生异常,finally 子句都会执行。

如果一个异常在 try 子句里(或者在 except 和 else 子句里)被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后再次被抛出。

三、常用案例

3.1 基本用法

try:
    # 可能引发异常的代码块
    result = 10 / 0
except ZeroDivisionError:
    # 捕获 ZeroDivisionError 异常
    print("除零错误发生")
else:
    # 如果没有发生异常时执行的代码
    print("计算结果:", result)
finally:
    # 无论是否发生异常,都会执行的代码
    print("无论如何都会执行的代码")

这个案例演示了 tryexceptelsefinally 的基本用法。try 块中的代码引发了 ZeroDivisionError 异常,然后在 except 块中捕获了该异常。如果没有异常发生,将执行 else 块中的代码。无论如何,finally 块中的代码都会执行。

3.2 捕获多个异常

try:
    # 可能引发多种异常的代码块
    num = int("abc")
    result = 10 / 0
except ValueError as ve:
    # 捕获 ValueError 异常
    print(f"ValueError: {ve}")
except ZeroDivisionError as zde:
    # 捕获 ZeroDivisionError 异常
    print(f"ZeroDivisionError: {zde}")
else:
    print("计算结果:", result)
finally:
    print("无论如何都会执行的代码")

这个案例展示了如何捕获多个异常。try 块中的代码引发了 ValueErrorZeroDivisionError 异常,分别在 except 块中捕获这两个异常。如果没有异常发生,将执行 else 块中的代码。

3.3 捕获所有异常

try:
    # 可能引发任何异常的代码块
    result = 10 / 0
except Exception as e:
    # 捕获所有异常
    print(f"发生异常: {e}")
else:
    print("计算结果:", result)
finally:
    print("无论如何都会执行的代码")

这个案例演示了如何捕获所有异常。try 块中的代码引发了 ZeroDivisionError 异常,而 except Exception as e 语句捕获了所有继承自 Exception 类的异常。无论是否有异常发生,都会执行 finally 块中的代码。

3.4 自定义异常

class CustomError(Exception):
    """自定义异常类"""

    def __init__(self, message="发生自定义异常"):
        self.message = message
        super().__init__(self.message)


def perform_custom_operation(value):
    """执行可能引发自定义异常的操作"""
    if value < 0:
        raise CustomError("数值不能为负数")
    return value * 2


# 使用自定义异常的案例
try:
    user_input = int(input("请输入一个非负整数: "))
    result = perform_custom_operation(user_input)
    print("操作结果:", result)
except CustomError as ce:
    print(f"捕获到自定义异常: {ce}")
except ValueError:
    print("输入无效,请输入一个整数")
else:
    print("操作成功完成")
finally:
    print("无论如何都会执行的代码")

这个案例演示了如何创建和使用自定义异常。CustomError 是一个继承自 Exception 的自定义异常类,通过 perform_custom_operation 函数执行可能引发自定义异常的操作。在 try 块中,用户输入一个整数,然后调用 perform_custom_operation 函数。如果输入的值为负数,将引发自定义异常 CustomError。在 except CustomError as ce 块中捕获到该异常,然后执行相应的处理逻辑。在 finally 块中,无论是否发生异常,都会执行相应的代码。

raise 是在 Python 中用于手动触发异常的关键字。它的作用是引发指定类型的异常,使得程序进入异常处理流程。

3.5 在循环中使用try-except

numbers = [1, 2, 3, 'four', 5]

for num in numbers:
    try:
        result = 10 / num
    except ZeroDivisionError:
        print("除零错误发生")
    except Exception as e:
        print(f"发生异常: {e}")
    else:
        print(f"计算结果: {result}")
    finally:
        print("无论如何都会执行的代码")

这个案例演示了如何在循环中使用 try-except。对于列表中的每个元素,都会尝试执行除法操作,捕获可能发生的 ZeroDivisionError 或其他异常。无论是否有异常发生,都会执行 finally 块中的代码。

以上案例可以帮助你更好地理解 try-except 的不同用法和场景。