← 全部文章

Python · 2018.10.05

异常处理

Yiuhang Chan更新于 2024.02.28约 12 分钟

异常(Exception)

在Python中,异常(Exception)是程序执行过程中发生的错误事件。当Python检测到一个错误时,它会引发一个异常。异常是Python用来管理程序执行中错误的一种机制。

异常的基本概念

  1. 异常 (Exception): 这是程序执行中发生的异常事件。在Python中,异常是一个对象,表示一个错误。
  2. 引发异常 (Raise an Exception): 当Python解释器遇到一个错误时,它会”引发”一个异常。程序员也可以在代码中显式地引发异常。
  3. 捕获异常 (Catch/Handle an Exception): 使用try和except语句来捕获并处理异常。这允许程序在发生异常时优雅地恢复,而不是完全崩溃。
  4. try块 (try block): 这是用来测试可能引发异常的代码块。
  5. except块 (except block): 当try块中的代码触发异常时执行的代码块。可以指定捕获特定类型的异常。
  6. finally块 (finally block): 无论是否发生异常,finally块中的代码都会执行。常用于执行清理操作,如关闭文件。
  7. else块 (else block): 如果try块没有引发异常,则执行else块中的代码。

异常类型

ValueError

当传递给函数的参数类型正确,但值不适当或不在预期范围内时,将引发ValueError。

def convert_to_int(text):
    try:
        return int(text)
    except ValueError:
        return "请提供一个有效的整数字符串"

print(convert_to_int("123"))  # 输出: 123
print(convert_to_int("abc"))  # 输出: 请提供一个有效的整数字符串

TypeError

当操作或函数应用于类型不正确的对象时,会引发TypeError。

def add_numbers(a, b):
    try:
        return a + b
    except TypeError:
        return "两个参数都必须是数字"

print(add_numbers(10, 20))    # 输出: 30
print(add_numbers(10, "20"))  # 输出: 两个参数都必须是数字

IndexError

当尝试访问序列中不存在的索引时,会引发IndexError。

my_list = [1, 2, 3]
try:
    print(my_list[3])
except IndexError:
    print("索引超出了列表的范围")

KeyError

当在字典中查找不存在的键时,会引发KeyError。

my_dict = {"name": "Alice", "age": 25}
try:
    print(my_dict["gender"])
except KeyError:
    print("键不存在")

IOError

当尝试执行一个与输入/输出相关的操作(如打开不存在的文件)时,会引发IOError(在Python 3中,通常是OSError或其子类)。

try:
    with open("nonexistent_file.txt") as f:
        content = f.read()
except IOError:
    print("文件打开失败")

ZeroDivisionError

当尝试将一个数字除以零时,会引发ZeroDivisionError。

try:
    result = 10 / 0
except ZeroDivisionError:
    print("除以零错误")

AttributeError

当尝试访问对象不存在的属性或方法时,会引发AttributeError。

class MyClass:
    def __init__(self):
        self.name = "ChatGPT"

try:
    obj = MyClass()
    print(obj.age)  # obj没有定义age属性
except AttributeError:
    print("属性不存在")

FileNotFoundError

在尝试打开一个不存在的文件时,Python 3中会引发FileNotFoundError,这是OSError的一个子类。

try:
    with open("some_nonexistent_file.txt") as f:
        content = f.read()
except FileNotFoundError:
    print("文件未找到")

ImportError

当尝试导入一个不存在的模块时,会引发ImportError。

try:
    import non_existent_module
except ImportError:
    print("模块无法导入")

OverflowError

当一个算术运算产生的结果太大而无法表示时,会引发OverflowError。

import math
try:
    # 这可能会引发OverflowError
    print(math.exp(1000))
except OverflowError:
    print("数值溢出")

NameError

当尝试访问一个尚未声明/定义的局部或全局变量时,会引发NameError。

try:
    print(undefined_variable)
except NameError:
    print("变量未定义")

RecursionError

当递归过深超过最大递归深度时,会引发RecursionError。这是RuntimeError的一个子类。

def recursive_function():
    recursive_function()

try:
    recursive_function()
except RecursionError:
    print("递归过深")

这些例子涵盖了Python中的一些其他常见异常类型。理解和处理这些异常对于编写稳健的Python程序至关重要。

SyntaxError

当Python解释器遇到语法错误时,会引发SyntaxError。这通常发生在代码编写不正确时。

try:
    exec("for i in range(5) print(i)")  # 缺少冒号
except SyntaxError:
    print("发生了语法错误")

IndentationError

当代码的缩进不正确时,会引发IndentationError,这是SyntaxError的一个子类。

try:
    exec("def foo():\nprint('Hello')")
except IndentationError:
    print("缩进错误")

AssertionError

当assert语句失败时,会引发AssertionError。assert用于调试阶段的自我检查。

try:
    assert 2 + 2 == 5, "计算错误"
except AssertionError as e:
    print("断言错误:", e)

KeyboardInterrupt

当用户中断程序执行(通常是通过按Ctrl+C),会引发KeyboardInterrupt。

try:
    while True:
        continue
except KeyboardInterrupt:
    print("程序被用户中断")

MemoryError

当程序运行时内存不足,无法执行操作时,会引发MemoryError。

try:
    large_list = [0] * 10**10
except MemoryError:
    print("内存不足")

StopIteration

在使用迭代器时,当没有更多的项可以返回时,会自动引发StopIteration。

iterator = iter([1, 2, 3])
next(iterator)  # 1
next(iterator)  # 2
next(iterator)  # 3
try:
    next(iterator)  # 迭代完毕
except StopIteration:
    print("迭代器没有更多元素")

EnvironmentError

EnvironmentError是在与外部环境(如操作系统)交互时可能遇到的错误的基类。在Python 3中,它被分为更具体的异常,如OSError。

其它

这并不是一个完整的列表:

  • ArithmeticError: 所有数值计算错误的基类。
  • BufferError: 与缓冲区相关的操作无法执行时。
  • EOFError: 当input()遇到文件结束标记(EOF)时。
  • FloatingPointError: 浮点计算错误。
  • LookupError: 索引或键查询错误的基类,IndexError和KeyError是它的子类。
  • ReferenceError: 当试图访问一个已经被垃圾回收器回收的资源时。
  • RuntimeError: 通常发生在检测到不属于其他类别的错误时。
  • SystemError: 解释器系统错误。
  • UnicodeError: Unicode相关的错误,是ValueError的一个子类。
  • UnicodeEncodeError: Unicode编码时的错误。
  • UnicodeDecodeError: Unicode解码时的错误。
  • UnicodeTranslateError: Unicode转换时的错误。

异常处理的语法

try:
    # 尝试执行的代码
    pass
except ExceptionType1:
    # 处理ExceptionType1
    pass
except ExceptionType2:
    # 处理ExceptionType2
    pass
except (ExceptionType3, ExceptionType4):
    # 处理多种异常
    pass
except:
    # 处理未指定的其他异常
    pass
else:
    # 如果没有异常发生,则执行此处代码
    pass
finally:
    # 无论是否有异常,都会执行此处代码
    pass

捕获特定异常

在Python中,可以使用try-except块来捕获特定类型的异常。这允许您对特定错误进行专门的错误处理。

try:
    # 可能会引发异常的代码
    result = 10 / 0
except ZeroDivisionError:
    print("捕获到除以零的异常")

捕获所有异常

捕获所有异常并且仅打印出错误信息,可以使用一个通用的 except Exception as e 块。这将捕获所有继承自 Exception 的错误(几乎包括了Python中所有的标准异常)

try:
    # 可能会引发异常的代码
    result = 10 / 0
except Exception as e:
    print(f"发生错误: {e}")

使用finally块

无论是否发生异常,finally块中的代码都会被执行。这非常适合用来执行清理操作,如关闭文件或释放资源。

try:
    file = open("test.txt", "r")
    data = file.read()
except IOError as e:
    print(f"读取文件时发生错误:{e}")
finally:
    file.close()
    print("文件已关闭")

主动抛出异常

可以使用raise语句来主动引发异常。这在需要根据特定条件显式地触发错误时非常有用。

def check_age(age):
    if age < 0:
        raise ValueError("年龄不能为负数")
    elif age < 18:
        print("未成年")
    else:
        print("成年")

try:
    check_age(-5)
except ValueError as e:
    print(f"捕获到异常:{e}")

使用断言(assert)

断言是一种调试辅助工具,用于检查一个条件是否为真。如果条件为假,将引发AssertionError。

def check_age(age):
    assert age >= 0, "年龄不能为负数"
    # 其余处理

try:
    check_age(-5)
except AssertionError as e:
    print(f"捕获到异常:{e}")

信息

  • 断言:通常用于内部一致性检查,表示“这里不可能出错,除非程序内部逻辑有问题”。
  • 异常:更适合于处理程序执行过程中可能遇到的预期错误情况,例如不满足输入条件、资源不可用等。

评论