Python 中使用 Try except 捕获异常

当文件访问、解析输入或网络调用等操作引发异常时,Python 程序会在运行时失败。处理这些try/except让您的应用程序保持响应,保留有用的上下文,并保证清理。

开始之前——核心规则

  • 捕获您期望的最具体的异常类型(例如,ValueError,FileNotFoundError),而不是包罗万象。
  • 使用else为成功之路和finally对于无论如何都必须运行的代码。
  • 更喜欢上下文管理器(with)用于文件和其他资源以简化清理。
  • 让意外的错误传播;记录它们并重新加注,而不是默默地吞下它们。
  • 保留包罗万象的处理程序(except Exception或者except BaseException)用于您可以快速失败或清晰报告的顶级边界。

步骤一:确定一项需要保护的危险操作。

raw = input("Select a fruit number (0-2): ")

步骤2:将操作包装在try/except并处理显式异常类型。

try:
    selection = ["apple", "pear", "banana"][int(raw)]
    print("You chose:", selection)
except ValueError:
    print("Not a number.")
except IndexError:
    print("Choice out of range.")

步骤3:当恢复相同时,对相关异常进行分组。

try:
    selection = ["apple", "pear", "banana"][int(raw)]
except (ValueError, IndexError) as e:
    print("Invalid selection:", type(e).__name__)

常见的具体例外包括OSError家庭(档案)、ValueErrorTypeError(数据),ZeroDivisionError(数学),以及KeyError/IndexError(收藏)。


方法 2 — 使用 else 和 finally 来分离成功和清理

步骤一:添加else仅当没有失败时才应运行的代码。

try:
    f = open("config.json", "r", encoding="utf-8")
except FileNotFoundError:
    print("No config file found.")
else:
    data = f.read()
    print("Loaded", len(data), "bytes.")
    f.close()

步骤2:添加finally无论尝试是否成功,都必须进行清理。

f = None
try:
    f = open("config.json", "r", encoding="utf-8")
    data = f.read()
except OSError as err:
    print("OS error:", err)
finally:
    if f:
        f.close()

方法 3 — 保护您的入口点以快速失败并记录

步骤一:将您的工作流程转移到main()功能。

def main():
    # core workflow
    # ...
    return 0

步骤2:将调用包装在顶层try/except记录意外错误并停止程序。

import logging, sys

logging.basicConfig(level=logging.INFO)

if __name__ == "__main__":
    try:
        code = main()
    except Exception:
        logging.exception("Unhandled error")
        sys.exit(1)
    sys.exit(code)

步骤3:如果未能向自动化工具发出运行失败的信号,则返回非零退出代码。

# in main(), return 1 or raise an exception when a critical step fails

方法 4 — 管理资源with(最终优于手动)

步骤一:用上下文管理器替换手动打开/关闭以强制及时发布。

from pathlib import Path

try:
    with Path("data.txt").open("r", encoding="utf-8") as f:
        print(f.readline().strip())
except FileNotFoundError:
    print("Create data.txt first.")

步骤2:仅将有风险的操作保留在受保护的块内,以避免捕获不相关的错误。

try:
    with open("image.png", "rb") as fh:
        blob = fh.read()
except OSError as e:
    print("File access failed:", e)
# decode/process blob in a separate block

方法 5 — 引发、重新引发和链接异常以清除错误路径

步骤一:当前提条件失败时引发特定异常。

def parse_age(s: str) -> int:
    if not s.isdigit():
        raise ValueError("age must contain only digits")
    age = int(s)
    if age < 0:
        raise ValueError("age cannot be negative")
    return age

步骤2:记录后重新引发意外错误,以便调用者也可以处理它们。

import logging

try:
    do_risky_thing()
except OSError as err:
    logging.error("OS error: %s", err)
    raise

步骤3:连锁异常raise ... from e在添加上下文的同时保留根本原因。

from pathlib import Path
import json

def load_json(path: str):
    try:
        text = Path(path).read_text(encoding="utf-8")
    except OSError as e:
        raise RuntimeError(f"Failed to read {path}") from e
    return json.loads(text)

方法 6 — 在边界处进行全面处理(谨慎使用)

步骤一:使用except Exception as e捕获任何非系统退出错误、记录详细信息并决定是否停止或重试。

import traceback

try:
    risky()
except Exception as e:
    print(f"Unexpected {type(e).__name__}: {e}")
    traceback.print_exc()  # full stack trace
    # decide: raise, return error, or abort

步骤2:只捕获BaseException如果你故意拦截KeyboardInterrupt或者SystemExit,然后立即重新加注。

try:
    service_loop()
except BaseException as e:
    print(f"Caught {type(e).__name__}; shutting down cleanly.")
    raise  # never swallow interrupts or SystemExit

方法 7 — 使用 ExceptionGroup 和 except* 处理多个失败 (Python 3.11+)

步骤一:提出一个ExceptionGroup当汇总并行或批量工作的错误时。

def run_tests(tests):
    errors = []
    for t in tests:
        try:
            t.run()
        except Exception as e:
            e.add_note(f"Test {t.name} failed")
            errors.append(e)
    if errors:
        raise ExceptionGroup("Batch failures", errors)

步骤2:使用except*仅处理组内匹配的异常类型。

try:
    run_tests(tests)
except* (ValueError, TypeError):
    print("Some data errors occurred.")
except* OSError:
    print("Some OS errors occurred.")

快速故障排除模式

  • 输入解析:换行int()或者float()except ValueError并重新提示用户。
  • 文件 I/O:捕获FileNotFoundError,PermissionError,或通用OSError,并切换到后备路径。
  • 网络/API 调用:捕获特定于库的超时/连接错误并实现带回退的有界重试。
  • 始终记录异常类型和消息;对于完整的痕迹,使用logging.exception()或者traceback.print_exc().

一些集中的模式,例如特定的except条款,else/finally,顶级防护将使您的 Python 程序更具弹性,而不会隐藏真正的错误。