杰瑞科技汇

Python错误exception怎么处理?

错误 vs. 异常

在 Python 中,我们通常区分两种情况:

Python错误exception怎么处理?-图1
(图片来源网络,侵删)

错误

错误通常是更严重的问题,导致程序无法继续运行,它们不是由异常处理机制捕获的,而是直接终止程序。

  • 语法错误:这是最常见的错误,在你编写代码时,如果不符合 Python 的语法规则,解释器在运行前就会报错。
  • 内存错误:当程序没有足够的内存可以分配时会发生,MemoryError

示例:语法错误

# 缺少冒号
if True
    print("Hello")

运行后会立即报错:

  File "<stdin>", line 1
    if True
        ^
SyntaxError: invalid syntax

异常

异常是程序在运行时发生的错误,它不会直接终止程序,而是创建一个“异常对象”并“抛出”它,如果程序中没有处理这个异常,程序就会崩溃并打印出 Traceback 信息。

Python错误exception怎么处理?-图2
(图片来源网络,侵删)

Python 内置了大量的异常类型,

  • NameError: 尝试访问一个未定义的变量。
  • TypeError: 对类型不兼容的对象执行操作。
  • ValueError: 传递给函数的参数类型正确,但值不合适。
  • IndexError: 访问序列中不存在的索引。
  • KeyError: 访问字典中不存在的键。
  • FileNotFoundError: 尝试打开一个不存在的文件。
  • ZeroDivisionError: 除数为零。

示例:各种异常

# NameError
print(undefined_var)
# TypeError
result = '5' + 2
# ValueError
num = int('abc')
# IndexError
my_list = [1, 2, 3]
print(my_list[5])
# KeyError
my_dict = {'a': 1, 'b': 2}
print(my_dict['c'])
# FileNotFoundError
with open('non_existent_file.txt', 'r') as f:
    content = f.read()
# ZeroDivisionError
print(10 / 0)

任何一个 print 语句都会导致程序崩溃,并显示类似下面的 Traceback:

Traceback (most recent call last):
  File "your_script.py", line X, in <module>
    print(undefined_var)
NameError: name 'undefined_var' is not defined

异常处理机制

为了防止程序因为异常而崩溃,Python 提供了 try...except 结构来捕获和处理异常。

Python错误exception怎么处理?-图3
(图片来源网络,侵删)

try...except 基本结构

这是最核心的异常处理结构。

try:
    # 尝试执行的代码块
    # 这里的代码可能会抛出异常
    code_that_might_fail()
except SomeException as e:
    # try 块中抛出了 SomeException 类型的异常,
    # 则执行这里的代码块
    # 变量 e 会接收到异常对象
    handle_the_exception(e)

示例:优雅地处理文件不存在

filename = 'data.txt'
try:
    f = open(filename, 'r')
    content = f.read()
    print(content)
    f.close()
except FileNotFoundError:
    print(f"错误:文件 '{filename}' 未找到,请检查文件名是否正确。")
print("程序继续执行...")

即使 data.txt 文件不存在,程序也不会崩溃,而是会打印出友好的错误提示,并继续执行后面的代码。

捕获多种异常

一个 try 块中可能发生多种不同的异常,你可以使用多个 except 块来分别处理它们。

a = 10
b = '0' # 如果改为 0, 则是 ZeroDivisionError; 如果改为 2, 则是 TypeError
try:
    result = a / b
    print(f"结果是: {result}")
except ZeroDivisionError:
    print("错误:不能除以零!")
except TypeError:
    print("错误:不能将整数和字符串进行除法运算。")

finally 子句

finally 块中的代码无论是否发生异常,都会被执行,它通常用于执行“清理”操作,比如关闭文件、释放数据库连接等。

file = None
try:
    file = open('data.txt', 'r')
    # 假设这里发生了异常
    print(file.read())
except FileNotFoundError:
    print("文件未找到!")
finally:
    # 无论 try 块成功还是失败,这里都会执行
    if file:
        file.close()
        print("文件已关闭。")
print("程序结束。")

raise 主动抛出异常

除了 Python 解释器会自动抛出异常,我们也可以使用 raise 语句主动抛出异常。

def check_age(age):
    if not isinstance(age, int):
        raise TypeError("年龄必须是整数")
    if age < 0:
        raise ValueError("年龄不能是负数")
    if age < 18:
        print("未成年")
    else:
        print("已成年")
# 正常调用
check_age(20)
# 主动抛出异常
try:
    check_age(-5)
except ValueError as e:
    print(f"捕获到异常: {e}")
try:
    check_age("twenty")
except TypeError as e:
    print(f"捕获到异常: {e}")

Python 内置异常层次结构

所有内置异常都继承自 BaseException 类,了解这个层次结构有助于你更好地选择要捕获的异常类型。

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- AttributeError
      +-- TypeError
      +-- ValueError
      +-- ... (还有很多其他类型)

最佳实践:捕获具体的异常

永远不要使用一个裸露的 except: 来捕获所有异常,这可能会隐藏你程序中的严重问题(SystemExitKeyboardInterrupt)。

不好的做法:

try:
    # 一些代码
    pass
except: # 捕获所有异常,包括程序退出信号
    pass

好的做法:

try:
    # 一些代码
    pass
except ValueError as e:
    # 只处理值错误
    print(f"发生值错误: {e}")
except KeyError as e:
    # 只处理键错误
    print(f"发生键错误: {e}")
except Exception as e:
    # 捕获其他所有预料之外的异常,并记录下来
    print(f"发生未知错误: {e}")

自定义异常

你可以通过继承 Python 的 Exception 类来创建自己的异常类型,这能让你的代码更具可读性和可维护性。

class InsufficientFundsError(Exception):
    """当账户余额不足时抛出此异常。"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        message = f"余额不足,当前余额: {balance}, 尝试取款: {amount}"
        super().__init__(message)
class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance
    def withdraw(self, amount):
        if amount > self.balance:
            # 主动抛出自定义异常
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount
        print(f"成功取款 {amount},当前余额: {self.balance}")
# 使用自定义异常
account = BankAccount(100)
try:
    account.withdraw(50)
    print("取款成功。")
    account.withdraw(100) # 这行会抛出异常
except InsufficientFundsError as e:
    print(f"取款失败: {e}")
    # 可以在这里进行恢复操作,比如通知用户等

概念 作用 示例
错误 SyntaxError, MemoryError 严重问题,程序无法继续 if True print('hi')
异常 NameError, TypeError, ValueError 运行时错误,可被捕获处理 int('hello')
捕获异常 try...except 防止程序崩溃,处理错误 try: ... except ValueError: ...
清理操作 finally 无论是否出错都执行 finally: file.close()
主动抛出 raise 人为地触发一个异常 raise ValueError("Bad value")
自定义异常 class MyError(Exception) 创建特定领域的错误类型 class InsufficientFundsError(...)

掌握异常处理是编写专业级 Python 代码的必备技能,记住这个黄金法则:“请求原谅比请求许可更容易”(EAFP: It's Easier to Ask for Forgiveness than Permission),也就是 try...except 风格,而不是在每次操作前都做大量的 if 判断。

分享:
扫描分享到社交APP
上一篇
下一篇