Python异常处理语法:try-except使用实例

Evan
Evan
发布时间:2026-11-03| 5人浏览过
原创

详细讲解Python中try-except异常处理语法的使用方法,通过多个实例演示如何捕获、处理和自定义异常,帮助你写出更健壮的Python代码。

你正在写一个读取文件的脚本,程序运行到一半突然报错 FileNotFoundError,整个进程直接退出——这是Python开发中最常遇到的场景之一。try-except 就是Python提供的异常处理机制,它允许你把可能出错的代码包裹起来,在错误发生时执行你预设的处理逻辑,而不是让程序直接崩溃。本文通过具体实例,完整讲解 try-except 的语法结构、常见用法和实际注意事项。

异常是什么

Python在运行期间遇到无法正常执行的情况时,会产生一个异常对象。如果这个异常没有被处理,程序就会终止并打印回溯信息(Traceback)。常见的异常类型包括:

异常类型典型触发场景
ZeroDivisionError除数为零
FileNotFoundError打开的文件不存在
ValueError函数收到类型正确但值不合法的参数
TypeError对不支持的类型执行操作
KeyError字典中不存在指定的键
IndexError列表索引超出范围

所有内置异常都继承自 BaseException,大多数我们需要捕获的异常继承自 Exception。了解这个继承关系,有助于理解后面按类型捕获异常的写法。

try-except 基本语法

try-except 的最基本形式是:把可能出错的代码放在 try 块中,把出错后要执行的代码放在 except 块中。

try:
    result = 10 / 0
except ZeroDivisionError:
    print("除数不能为零")

运行这段代码,输出如下:

# 示例输出
除数不能为零

程序不会崩溃,而是执行了 except 中的打印语句。这里的 ZeroDivisionError 指定了要捕获的异常类型。如果 try 块中抛出的异常类型与 except 后面写的不匹配,异常仍然不会被捕获,程序照样会终止。

Python异常处理语法:try-except使用实例
图1:try-except 基本执行流程——异常匹配时进入 except 块,否则程序终止

捕获多种异常

实际代码中,一段逻辑可能抛出不同类型的异常。你可以写多个 except 分支分别处理,也可以在一个 except 中用元组同时捕获多种类型。

多个 except 分支

data = {"name": "Alice"}

try:
    value = data["age"]        # 可能 KeyError
    number = int(value)        # 可能 ValueError
except KeyError as e:
    print(f"字典中缺少键: {e}")
except ValueError as e:
    print(f"值转换失败: {e}")

运行这段代码会输出:

# 示例输出
字典中缺少键: 'age'

Python会按照 except 分支的书写顺序从上到下匹配。一旦某个分支匹配成功,就执行该分支并跳过后续的 except 块。as e 把异常对象绑定到变量 e,可以用来获取具体的错误信息。

用元组捕获多种异常

如果几种异常的处理方式相同,可以合并成一个分支:

try:
    result = int("abc")
except (ValueError, TypeError) as e:
    print(f"输入数据有误: {e}")
编写 except 分支时,把更具体的异常类型放在前面。例如 FileNotFoundError 是 OSError 的子类,如果 except OSError 写在前面,FileNotFoundError 的分支永远不会被执行。

完整结构:try-except-else-finally

try 语句的完整形式包含四个部分,每个部分有明确的执行时机:

try:
    f = open("config.txt", "r")
    content = f.read()
except FileNotFoundError:
    print("配置文件不存在,将使用默认配置")
    content = "default=true"
else:
    print(f"成功读取配置,共 {len(content)} 个字符")
finally:
    print("无论是否出错,这里都会执行")
    # 如果文件打开成功,在这里关闭
    if 'f' in dir():
        f.close()
  • try:放置可能抛出异常的代码。
  • except:当 try 块中发生指定异常时执行。
  • else:只在 try 块没有发生任何异常时执行。适合放"成功后才需要做"的逻辑,让 try 块保持简短。
  • finally:无论是否发生异常都会执行。通常用来释放资源(关闭文件、断开连接等)。
Python异常处理语法:try-except使用实例
图2:try-except-else-finally 四部分的执行路径——两条路径最终都经过 finally

获取异常信息

通过 as 关键字把异常对象绑定到变量后,可以获取详细的错误描述。结合 traceback 模块,还能拿到完整的调用栈信息,这在记录日志时非常有用。

import traceback

def divide(a, b):
    return a / b

try:
    result = divide(5, 0)
except ZeroDivisionError as e:
    print(f"异常类型: {type(e).__name__}")
    print(f"异常信息: {e}")
    print("调用栈:")
    traceback.print_exc()

示例输出:

# 示例输出
异常类型: ZeroDivisionError
异常信息: division by zero
调用栈:
Traceback (most recent call last):
  File "demo.py", line 6, in <module>
    result = divide(5, 0)
  File "demo.py", line 3, in divide
    return a / b
ZeroDivisionError: division by zero

在正式项目中,通常会用 logging.exception() 代替 print,它会自动把调用栈写入日志文件。

实用场景:用户输入验证

下面是一个实际的例子——循环接收用户输入,直到拿到合法的整数为止:

def get_positive_integer(prompt_text):
    """反复提示用户,直到输入一个正整数"""
    while True:
        try:
            value = int(input(prompt_text))
            if value <= 0:
                raise ValueError("需要正整数")
            return value
        except ValueError as e:
            print(f"输入无效: {e},请重新输入")

# 调用示例
# age = get_positive_integer("请输入年龄: ")

这个例子展示了两个要点:第一,try-except 可以和循环配合,实现"重试到成功"的模式;第二,你可以用 raise 手动抛出异常来统一处理不同类型的错误(这里把"值不合法"和"类型转换失败"统一成 ValueError)。

实用场景:文件操作与 with 语句

处理文件时,try-except 经常和 with 语句配合使用。with 可以自动管理文件关闭,即使在 except 中也不必手动调用 close():

import json

def load_config(filepath):
    """读取JSON配置文件,出错时返回默认配置"""
    default = {"debug": False, "port": 8080}
    try:
        with open(filepath, "r", encoding="utf-8") as f:
            config = json.load(f)
        return config
    except FileNotFoundError:
        print(f"文件 {filepath} 不存在,使用默认配置")
        return default
    except json.JSONDecodeError as e:
        print(f"JSON格式错误(行 {e.lineno}): {e.msg}")
        return default

config = load_config("settings.json")
print(config)

这段代码分别处理了"文件不存在"和"JSON格式不合法"两种情况,每种情况都有明确的提示信息并返回一个可用的默认配置,保证程序不会因为配置文件的问题就无法启动。

Python异常处理语法:try-except使用实例
图3:文件操作中异常处理的完整步骤——每种错误都有对应的处理和降级方案

自定义异常

当内置异常类型无法准确描述你的业务错误时,可以通过继承 Exception 来创建自定义异常类:

class InsufficientBalanceError(Exception):
    """余额不足异常"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(
            f"余额不足: 当前余额 {balance},尝试支出 {amount}"
        )

class Account:
    def __init__(self, balance):
        self.balance = balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientBalanceError(self.balance, amount)
        self.balance -= amount
        return self.balance

# 使用
account = Account(100)
try:
    account.withdraw(150)
except InsufficientBalanceError as e:
    print(e)
    print(f"差额: {e.amount - e.balance}")

示例输出:

# 示例输出
余额不足: 当前余额 100,尝试支出 150
差额: 50

自定义异常的好处是:调用方可以通过异常类型精确区分不同的错误情况,并且通过异常对象的属性获取详细的上下文信息,而不是只能解析错误字符串。

常见错误写法与改进

1. 裸 except 捕获一切

# 不推荐
try:
    do_something()
except:
    pass

这种写法会吞掉所有异常,包括 KeyboardInterrupt(Ctrl+C)和 SystemExit。结果是程序出了错你完全不知道,甚至无法正常终止。正确做法是至少指定 Exception:

# 推荐
try:
    do_something()
except Exception as e:
    logging.error(f"操作失败: {e}")

2. try 块包含过多代码

# 不推荐:整个函数体都在 try 里
try:
    data = load_data()
    cleaned = clean_data(data)
    result = process(cleaned)
    save(result)
except Exception as e:
    print(f"出错了: {e}")

# 推荐:只包裹真正可能出错的部分
data = load_data()
cleaned = clean_data(data)
try:
    result = process(cleaned)
except ValueError as e:
    print(f"数据处理出错: {e}")
    result = fallback_process(cleaned)
save(result)

try 块越大,你越难判断异常到底是哪一行抛出的,也越容易把不该忽略的错误一并吞掉。把 try 的范围缩小到真正需要保护的代码,让错误定位更准确。

3. 用异常控制正常流程

# 不推荐
try:
    value = my_dict[key]
except KeyError:
    value = default_value

# 推荐:用字典自带的方法
value = my_dict.get(key, default_value)

如果有更直接的方式(如 .get()、in 检查)能避免异常,优先使用。try-except 应该处理的是"异常情况"而不是"正常分支"。不过在Python中,这条边界并不绝对——EAFP(先尝试再处理异常)本身是Python推荐的风格,关键是根据代码的可读性做判断。

Python异常处理语法:try-except使用实例
图4:try-except 使用要点总结——六个核心原则帮助写出健壮的异常处理代码

异常链与 raise from

在处理一个异常时,有时你需要抛出一个不同类型的异常,同时保留原始错误信息。Python 3提供了 raise ... from ... 语法来建立异常链:

class ConfigError(Exception):
    pass

def load_port(filepath):
    try:
        with open(filepath) as f:
            return int(f.read().strip())
    except (FileNotFoundError, ValueError) as e:
        raise ConfigError(f"无法加载端口配置: {filepath}") from e

try:
    port = load_port("port.txt")
except ConfigError as e:
    print(e)
    print(f"原始错误: {e.__cause__}")

示例输出(文件不存在时):

# 示例输出
无法加载端口配置: port.txt
原始错误: [Errno 2] No such file or directory: 'port.txt'

from e 把原始异常挂在新异常的 __cause__ 属性上。打印完整 Traceback 时,Python会显示两个异常及它们之间的因果关系,方便排查问题根源。

小结

try-except 是Python中处理运行时错误的基本工具。掌握它的核心在于三点:明确你要捕获什么异常、捕获后要怎么处理、以及如何确保资源被正确释放。把这三点想清楚,代码就不会出现"出了错但不知道哪里出了错"的情况。

在实际项目中,建议遵循以下做法:

  1. 始终指定具体的异常类型,按从具体到一般的顺序排列 except 分支。
  2. 用 as e 获取异常信息并记录日志,不要用 pass 默默吞掉错误。
  3. 优先使用 with 语句管理资源,减少对 finally 的依赖。
  4. 业务逻辑复杂时,定义自定义异常类来区分不同的错误类型。
  5. 用 raise from 保留异常链,便于定位问题的根本原因。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。