当文件访问、解析输入或网络调用等操作引发异常时,Python 程序会在运行时失败。处理这些try/except让您的应用程序保持响应,保留有用的上下文,并保证清理。
开始之前——核心规则
- 捕获您期望的最具体的异常类型(例如,
ValueError,FileNotFoundError),而不是包罗万象。 - 使用
else为成功之路和finally对于无论如何都必须运行的代码。 - 更喜欢上下文管理器(
with)用于文件和其他资源以简化清理。 - 让意外的错误传播;记录它们并重新加注,而不是默默地吞下它们。
- 保留包罗万象的处理程序(
except Exception或者except BaseException)用于您可以快速失败或清晰报告的顶级边界。
方法 1 — 捕获特定异常(推荐)
步骤一:确定一项需要保护的危险操作。
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家庭(档案)、ValueError和TypeError(数据),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 程序更具弹性,而不会隐藏真正的错误。






