2026/5/21 13:36:03
网站建设
项目流程
做期货到哪个网站看新闻,茌平做网站,内网网站模板,太原网站 制作Day 17#xff1a;【99天精通Python】异常处理 - 让程序稳如泰山
前言
欢迎来到第17天#xff01;
在编程的世界里#xff0c;不出 bug 是不可能的。即便是最顶尖的程序员#xff0c;也无法保证代码永远不出错。用户可能会输入非法数据#xff0c;文件可能突然被删除…Day 17【99天精通Python】异常处理 - 让程序稳如泰山前言欢迎来到第17天在编程的世界里不出 bug 是不可能的。即便是最顶尖的程序员也无法保证代码永远不出错。用户可能会输入非法数据文件可能突然被删除网络可能会断开。如果程序一遇到错误就直接崩溃闪退用户体验会非常差。异常处理 (Exception Handling)就是给程序穿上一层防弹衣当意外发生时我们能优雅地捕获错误并给出友好的提示而不是让程序直接挂掉。本节内容什么是异常try...except基本结构捕获多种异常else和finally的作用主动抛出异常raise自定义异常类实战练习一、什么是异常 (Exception)异常是指程序在运行过程中发生的错误它会打断指令的正常执行。常见的异常类型SyntaxError: 语法错误通常在运行前就会报错。NameError: 尝试访问一个未定义的变量。TypeError: 类型不匹配例如数字 字符串。ZeroDivisionError: 除数为 0。IndexError: 列表索引越界。KeyError: 字典中不存在该键。FileNotFoundError: 打开不存在的文件。二、基本语法try…except我们使用try块包含可能出错的代码用except块来处理错误。2.1 基本结构try:# 可能会报错的代码numint(input(请输入一个数字: ))result10/numprint(f计算结果:{result})exceptZeroDivisionError:# 当发生除以0错误时执行print(错误除数不能为0)exceptValueError:# 当输入的不是数字时执行print(错误请输入有效的整数)2.2 获取异常信息有时我们需要知道具体的报错信息可以使用as关键字。try:print(1/0)exceptZeroDivisionErrorase:print(f捕获到错误:{e})# 捕获到错误: division by zero2.3 捕获所有异常 (慎用)可以使用Exception捕获所有类型的运行时错误。但通常不推荐这样做因为这会掩盖一些意想不到的 bug比如变量名写错。try:# 复杂逻辑passexceptExceptionase:print(f发生未知错误:{e})三、完善结构else 与 finally异常处理还有两个可选的子句else和finally。else: 当try块没有发生异常时执行。finally:无论是否发生异常最终都会执行常用于清理资源如关闭文件、断开数据库。defdivision_test(x,y):try:resultx/yexceptZeroDivisionError:print(Error: 除数不能为0)else:print(fSuccess: 结果是{result})finally:print(--- 执行完毕 ---)print(第一次测试:)division_test(10,2)print(\n第二次测试:)division_test(10,0)运行结果第一次测试: Success: 结果是 5.0 --- 执行完毕 --- 第二次测试: Error: 除数不能为0 --- 执行完毕 ---四、主动抛出异常raise有时候并不是代码出错了而是业务逻辑不满足我们需要主动报错通知调用者。这时使用raise关键字。defset_age(age):ifage0orage150:# 主动抛出一个值错误raiseValueError(年龄必须在 0 到 150 之间)print(f年龄设置为:{age})try:set_age(200)exceptValueErrorase:print(f设置失败:{e})五、自定义异常虽然 Python 内置了很多异常但在大型项目中为了更清晰地表达业务错误我们通常会自定义异常类。只需要继承Exception类即可。# 定义一个余额不足异常classInsufficientFundsError(Exception):passclassBankAccount:def__init__(self,balance):self.balancebalancedefwithdraw(self,amount):ifamountself.balance:# 抛出自定义异常raiseInsufficientFundsError(f余额不足当前:{self.balance}, 需要:{amount})self.balance-amountprint(f取款成功剩余:{self.balance})accountBankAccount(100)try:account.withdraw(200)exceptInsufficientFundsErrorase:print(f交易拒绝:{e})六、实战练习练习1健壮的整数输入器编写一个函数get_integer(prompt)循环提示用户输入内容直到用户输入一个合法的整数为止。defget_integer(prompt):whileTrue:user_inputinput(prompt)try:valueint(user_input)returnvalue# 成功转换返回结果并退出循环exceptValueError:print(f输入无效{user_input} 不是一个整数请重试。)# 测试ageget_integer(请输入你的年龄: )print(f你的年龄是:{age})练习2安全的文件读取编写一个程序读取文件如果文件不存在提示用户如果文件编码错误也提示用户无论如何最后都要打印操作结束。defsafe_read(filename):try:withopen(filename,r,encodingutf-8)asf:print(f.read())exceptFileNotFoundError:print(f错误: 文件 {filename} 未找到。)exceptUnicodeDecodeError:print(f错误: 文件 {filename} 编码格式不对无法读取。)exceptExceptionase:print(f发生未知错误:{e})finally:print(--- 读取操作结束 ---)# 测试safe_read(not_exist.txt)七、常见问题Q1try块里应该放多少代码越少越好。只把可能报错的那几行关键代码放进去。如果在try里放了几百行代码一旦报错你很难定位到底是哪一行出了问题。Q2except可以不写类型吗可以写except:但这等同于捕获所有异常包括CtrlC中断。这是一种极坏的编程习惯强烈建议至少写except Exception:。Q3return和finally谁先执行如果try块中有returnfinally会在return之前执行。千万不要在finally里面写return否则会覆盖掉原本的返回值。八、小结无错误发生异常是否异常处理流程try: 执行代码执行 else (可选)匹配 except 类型?执行 except 块 (处理错误)向上抛出异常 (程序崩溃)执行 finally (无论如何都执行)其他核心raise: 主动报错自定义异常: 继承 Exception关键要点预判错误用try...except包裹可能出错的代码。精准捕获尽量指定具体的异常类型如ValueError避免使用笼统的Exception。善后处理资源释放如关闭文件一定要放在finally中。业务逻辑不满足条件时可以用raise主动中断程序。九、课后作业简易除法器编写程序接收两个用户输入的数字进行除法运算。需要处理输入非数字、除数为0、以及未知错误。列表越界保护编写一个函数safe_get(lst, index)接收列表和索引。如果索引有效返回对应的元素如果索引越界捕获IndexError并返回None而不是报错。用户注册系统定义一个register(username, password)函数。如果用户名长度小于3抛出自定义异常UsernameTooShortError。如果密码长度小于6抛出自定义异常PasswordTooShortError。编写调用代码捕获并打印这些错误。下节预告Day 18常用内置模块 (JSON, Datetime, Random)- 之前简单提过标准库明天我们将深入讲解开发中最离不开的几个模块学会处理时间、数据交换和随机事件。系列导航上一篇Day 16 - 面向对象编程(下)下一篇Day 18 - 常用内置模块待更新