查看全课大纲(第 20 / 51 节)
  1. 1.为什么人人都该学点编程?
  2. 2.计算机与程序设计:你的电脑到底在“想”什么?
  3. 3.Python 这门语言,到底有什么魔力?
  4. 4.Python 开发环境配置:如何拥有你的第一个“编程工具箱”?
  5. 5.如何安装一个更强大的代码编辑器?
  6. 6.汇率兑换1.0:你的第一个“钱生钱”小程序
  7. 7.你的第一行代码,藏着哪些秘密?
  8. 8.汇率兑换2.0(上):让程序看懂“CNY”和“USD”
  9. 9.汇率兑换程序,如何让它“聪明”地判断币种?
  10. 10.汇率兑换程序能一直运行,直到我喊停吗?
  11. 11.汇率兑换4.0:如何把“算钱”功能打包成积木?
  12. 12.汇率兑换5.0:给你的程序穿上“结构化”的西装
  13. 13.怎么用 Python 画一个会动的五角星?
  14. 14.如何让程序自动画出不同大小的五角星?
  15. 15.函数自己调用自己,会发生什么?
  16. 16.用递归画出神奇的分形树
  17. 17.Python 怎么计算你一天躺着不动能消耗多少热量?
  18. 18.如何让程序“活”起来,持续为你服务?
  19. 19.如何让 BMR 计算器更“聪明”?
  20. 20.当程序遇到“不按套路出牌”的用户怎么办?
  21. 21.怎么用 Python 模拟一个“滚雪球”式的存钱计划?
  22. 22.如何用列表记录每一周的存款?
  23. 23.如何让程序自己数数?—— 用 for 循环解放你的双手
  24. 24.52周存钱挑战4.0:你的存款计算器能有多灵活?
  25. 25.52周存钱挑战:怎么根据日期自动查存款?
  26. 26.Python 怎么判断一年中的第几天?
  27. 27.列表 vs 元组:哪个更适合存储月份天数?
  28. 28.用集合给月份分个队,换个思路算天数
  29. 29.把月份和天数“锁”在一起:用字典给数据配个对
  30. 30.Python 怎么判断密码强弱?
  31. 31.Python 怎么给密码设置“防沉迷”系统?
  32. 32.Python 怎么把密码保存到文件里?
  33. 33.Python 怎么读取文件里的密码?
  34. 34.Python 怎么把密码检查工具“打包”起来?
  35. 35.Python 怎么把文件操作也“打包”起来?
  36. 36.计算机怎么“扔骰子”?——用Python模拟随机事件
  37. 37.如何用 Python 模拟掷两个骰子?
  38. 38.怎么用 Python 把骰子轨迹画出来?
  39. 39.骰子点数分布长啥样?用直方图一眼看穿!
  40. 40.用科学计算库让骰子程序“起飞”
  41. 41.空气质量指数怎么算?手把手教你写一个AQI计算器
  42. 42.空气质量指数计算:从零开始,让程序看懂空气
  43. 43.如何读取空气质量数据文件并找出空气质量最好的五个监测点?
  44. 44.JSON 数据怎么变成 Excel 表格?—— 让数据换个“马甲”
  45. 45.Python 怎么让程序自己判断文件类型?
  46. 46.如何让程序自己上网查空气质量?
  47. 47.用美味的汤来解析网页:Beautiful Soup 入门
  48. 48.如何让爬虫自动抓取全国所有城市的空气质量?
  49. 49.爬到的数据怎么存下来?—— 把全国空气质量数据保存为CSV文件
  50. 50.用 pandas 玩转空气质量数据:找出全国空气最好和最差的城市
  51. 51.空气质量数据怎么“洗”干净,还能画成图?

当程序遇到“不按套路出牌”的用户怎么办?

约 15 分钟

小象实战讲义 · Python 入门:8 个小项目边玩边学

上一节,我们让BMR计算器变得“善解人意”,能在一行里接收所有信息。但程序还是有点“玻璃心”——只要用户输入的不是数字,比如把“70”输成了“七十”,它就会直接崩溃,留下一堆看不懂的错误代码。

这一节,我们就来给程序穿上“防弹衣”,让它遇到“不按套路出牌”的用户时,也能优雅地处理,给出友好的提示,而不是直接“摆烂”崩溃。你的程序将变得更健壮、更专业。

💡 核心导读

  • 问题引入:模拟一个“捣蛋”用户,看看程序崩溃时有多吓人。
  • 新知识点:认识Python的“保镖”——try...except异常处理机制。
  • 实战应用:为BMR计算器添加异常处理,让它能从容应对各种错误输入。
  • 知识巩固:回顾本章所学,并预告下一个处理“一系列数据”的精彩项目。

一、当程序遇到“捣蛋鬼”

还记得我们上节课末尾留下的悬念吗?如果用户不输入数字,而是输入了“七十”、“一米八”这样的文字,程序会怎样?让我们来当一回“捣蛋鬼”用户,亲自试试看。

假设我们运行程序后,故意乱输入:

  • 是否退出?n(不退出)
  • 请输入信息:男 七十 175 25 (注意,体重这里写的是“七十”)

猜猜会发生什么?

程序会瞬间“爆炸”,在屏幕上打印出一大段红色的错误信息,最后以 ValueError: could not convert string to float: '七十' 结尾,然后彻底停止运行。

对于一个完全不懂代码的用户来说,这简直就像电脑突然蓝屏一样让人恐慌。他们会觉得:“这什么破程序,一点也不好用!” 这可不是我们想看到的。

我们的目标:就算用户输错了,程序也应该温柔地提醒,比如“请输入正确的数字哦~”,然后让用户有机会重新输入,而不是直接“死”给你看。

二、请出程序的“保镖”:try...except

Python早就为我们想到了这种情况,并提供了一个超级好用的“保镖”机制——异常处理,对应的代码结构是 try...except。

你可以这样理解:

  • try(尝试):把你觉得可能会出问题的代码放进这个“保护罩”里。
  • except(除了/捕获):如果“保护罩”里的代码真的出错了(发生了“异常”),就执行 except 后面的代码来“兜底”。

它的基本长相是这样的:

try:
    # 把可能出问题的代码放在这里
    # 例如:把用户输入的字符串转换成数字
    risky_code_here
except 错误类型1:
    # 如果发生了“错误类型1”,就执行这里的代码
    handle_error1
except 错误类型2:
    # 如果发生了“错误类型2”,就执行这里的代码
    handle_error2
except Exception:
    # 这是一个“万能捕获器”,可以捕获绝大多数运行时错误
    handle_all_other_errors

小提示:上面最后一种也可以简写成裸的 except:,但它会“贪婪地”连 KeyboardInterrupt(Ctrl+C 中断)、SystemExit 这类系统级信号也一并捕获,导致你连想强制退出程序都退不掉。所以正式代码里推荐写 except Exception:——它覆盖普通错误,却放行了系统退出信号。

它是怎么工作的?

  1. Python先尝试执行 try 里面的代码。
  2. 如果一切顺利,没有错误,它就跳过所有 except,继续执行后面的程序。
  3. 如果 try 里面的代码出错了,Python就会立刻停止 try 块内的执行,然后从上到下检查是哪个 except 能“抓住”这个错误。
  4. 找到匹配的 except 后,就执行它里面的“兜底”代码。执行完后,程序会继续正常往下走(而不是崩溃)。

这就好比你去尝试一个高难度动作(try),旁边站着教练(except)。你做成功了,万事大吉。你做失败了,教练立刻扶住你,防止你摔伤,并给你指导,然后你可以继续练习。

三、给BMR计算器穿上“防弹衣”

现在,我们就用这个“保镖”来升级我们的BMR计算器。核心思路是:把用户输入、分割字符串、转换数字类型、计算BMR这一整套流程,都放到 try 的保护罩里。

第1步:识别“危险地带”

在我们当前的代码中,哪里最容易“爆炸”? 答案就是把字符串转换成数字的这三行:

weight = float(str_list[1])   # 把体重字符串转成浮点数
height = float(str_list[2])   # 把身高字符串转成浮点数
age = int(str_list[3])        # 把年龄字符串转成整数

(上面这三行是从完整程序里摘出来的”危险地带”,str_list 由上一节的 input_str.split(' ') 得到,所以单独运行会找不到它——下面第 2 步我们会把它们完整地放回程序里。) 如果 str_list[1] 是 "七十",float("七十") 肯定会失败。

第2步:构建“保护罩”

我们用 try 把从输入到计算的整个逻辑包起来。同时,我们要捕获最常见的错误——ValueError(值错误,通常就是类型转换失败)。

下面是升级到4.0版本的完整代码。注意:为了你能直接复制运行,我们把整个程序写在一个代码块里,并且用固定值代替了 input()。

"""
    作者:小象教研组
    功能:BMR计算器
    版本:4.0
    描述:处理用户的异常输入,让程序更健壮
"""

def main():
    """主函数"""
    # 原程序这里用 input('是否退出程序(y/n)?'),为了方便运行,我们固定为 'n'(不退出)
    y_or_n = 'n'

    while y_or_n != 'y':
        print('请输入以下信息,用空格分割')
        # 原程序用 input('性别 体重(kg) 身高(cm) 年龄:')
        # 我们用一个会引发错误的输入来演示:'男 七十 175 25'
        input_str = '男 七十 175 25'
        print(f'用户输入的是:{input_str}')
        str_list = input_str.split(' ')

        try:
            # 尝试执行可能出错的代码
            gender = str_list[0]
            weight = float(str_list[1])  # 这里可能会出错!
            height = float(str_list[2])  # 这里可能会出错!
            age = int(str_list[3])       # 这里可能会出错!

            if gender == '男':
                bmr = (13.7 * weight) + (5.0 * height) - (6.8 * age) + 66
            elif gender == '女':
                bmr = (9.6 * weight) + (1.8 * height) - (4.7 * age) + 655
            else:
                bmr = -1

            if bmr != -1:
                print('您的性别:{},体重:{}公斤,身高:{}厘米,年龄:{}岁'.format(gender, weight, height, age))
                print('您的基础代谢率:{}大卡'.format(bmr))
            else:
                print('暂不支持该性别')
        except ValueError:
            # 专门捕获 ValueError(例如:float('七十') 失败)
            print('⚠️  请输入正确的数字信息!')
        except:
            # 捕获所有其他未知错误
            print('⚠️  程序发生未知异常,请检查输入格式。')

        print()  # 输出空行
        # 演示一次后,我们让程序退出循环
        y_or_n = 'y'

main()
请输入以下信息,用空格分割
用户输入的是:男 七十 175 25
⚠️  请输入正确的数字信息!

看!程序没有崩溃,而是友好地提示我们“请输入正确的数字信息!”。然后它正常地打印了一个空行,并准备进行下一次循环(在我们的例子里,我们直接让它退出了)。

💡 核心改动:我们只新增了 try...except 结构,就把程序的“抗揍”能力提升了一个等级。这就是“平滑引入新知识点”的魅力——只做一件事,但效果立竿见影。

第3步:应对更多“捣蛋”方式

用户可能不只是输错数字,还可能少输入信息,比如只输入了“男”,然后就回车了。这会导致 str_list[1] 根本不存在,引发 IndexError(索引错误)。

我们可以像添加 ValueError 一样,添加对 IndexError 的专门处理:

try:
    # ... (尝试执行的代码)
except ValueError:
    print('⚠️  请输入正确的数字信息!')
except IndexError:
    print('⚠️  输入的信息不足,请按格式输入:性别 体重(kg) 身高(cm) 年龄')
except:
    print('⚠️  程序发生未知异常,请检查输入格式。')

这样,程序就能针对不同的“捣蛋”方式,给出更精确的提示了!

四、为什么异常处理如此重要?

想象一下:

  • 没有异常处理:用户输错 → 程序崩溃,红字刷屏 → 用户愤怒,可能再也不用了。
  • 有异常处理:用户输错 → 程序提示“输入有误哦,请重试” → 用户觉得“这程序真智能,还提醒我”,欣然重试。

良好的异常处理是专业软件的标志。它不仅能提升用户体验,也能帮助开发者(也就是未来的你!)更快地定位和修复问题。在后续更复杂的项目中,它将是保证程序稳定运行的基石。

📝 动手练一练

  1. 【必做】体验“防弹衣”:将上面完整的4.0版本代码复制到你的编辑器中运行。然后,修改 input_str 的值,分别测试以下几种“捣蛋”输入,观察程序的反应:

    • '男 70 175 二十五' (年龄不是数字)
    • '男 70' (信息不足)
    • 'Unknown 70 175 25' (性别不支持)
    • '男 70 175 25 多余' (信息过多)
  2. 【挑战】自定义友好提示:现在的提示信息比较通用。请你修改 except 块里的 print 语句,让提示变得更友好、更有趣,甚至带点“卖萌”属性。例如:“哎呀,体重好像输错了呢,要输入像70这样的数字哦~”

👉 点击查看第2题思路提示

思路:在 except 块中,你可以使用任何字符串。发挥你的创意!比如:

except ValueError:
    print('(。•́︿•̀。) 看起来体重、身高或年龄中混入了文字,请检查后输入纯数字哦~')
except IndexError:
    print('(´・ω・`)? 信息好像没填全呢,请按“性别 体重 身高 年龄”的格式填写,用空格分开。')

记住,让程序有“人情味”,是吸引用户的一大法宝。

  1. 【回顾】模块化练习(来自视频课后练习):在3.0版本中,我们计算BMR的公式是直接写在主循环里的。请尝试将这部分计算逻辑封装成一个独立的函数,例如 calculate_bmr(gender, weight, height, age)。这会让你的代码结构更清晰,也是专业程序员的好习惯。
👉 点击查看第3题参考答案

思路:定义一个函数,接收性别、体重、身高、年龄四个参数,根据性别选择公式计算,并返回BMR值。

def calculate_bmr(gender, weight, height, age):
    """
    根据性别、体重、身高、年龄计算基础代谢率(BMR)
    参数: gender(字符串), weight(浮点数), height(浮点数), age(整数)
    返回: BMR值(浮点数),如果性别不支持则返回-1
    """
    if gender == '男':
        return (13.7 * weight) + (5.0 * height) - (6.8 * age) + 66
    elif gender == '女':
        return (9.6 * weight) + (1.8 * height) - (4.7 * age) + 655
    else:
        return -1

# 测试一下这个函数
print(calculate_bmr('男', 70, 175, 25))  # 应输出一个计算后的数值
print(calculate_bmr('女', 60, 165, 30))  # 应输出一个计算后的数值
print(calculate_bmr('其他', 70, 175, 25)) # 应输出 -1
1730.0
1387.0
-1

然后,你可以在主程序的 try 块中,用 bmr = calculate_bmr(gender, weight, height, age) 来调用这个函数,替换掉原来的if-else计算部分。

本章小结

恭喜你完成了《基础代谢率计算》这个项目的全部四个版本!让我们来回顾一下这条平滑而有趣的升级之路:

  • 1.0 从零开始:我们认识了整数和浮点数,学会了用 type() 查看类型,用 int()/float() 进行转换,做出了能计算单次BMR的程序。
  • 2.0 持续交互:我们巩固了 while 循环和 if-else 判断,让程序能够“不厌其烦”地一直为不同的用户服务。
  • 3.0 善解人意:我们学习了字符串的 split() 分割和 format() 格式化输出,让用户可以在一行内输入所有信息,并且输出结果带上单位,体验更佳。
  • 4.0 坚固耐用(本节):我们引入了 try...except 异常处理机制,为程序穿上了“防弹衣”,让它能优雅地处理用户的错误输入,不再轻易崩溃。

从处理一个数据(单次计算),到处理多次交互,再到处理一串信息(字符串分割),最后到处理意外情况,我们每一步都只学一个新东西,但组合起来,你已经做出了一个相当实用和健壮的小工具!

📋 行动清单

学完本章,你可以立刻:

  • 运行你的4.0版本BMR计算器,并用家人或朋友的真实数据测试一下。
  • 思考一下,你平时用的App或软件,在你输错时是怎么提示你的?尝试将那种友好的提示风格用到你的程序里。
  • 准备好迎接下一个挑战——我们将告别处理“单个”或“几个”数据的时代,进入处理“一系列”数据的新篇章!

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第4章代码包:基础代谢率计算(含全部版本 4 个 .py)
    ZIP · 3KB
    下载
看图文没弄懂?展开看本节视频讲解(约 15 分钟)
📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)