Ubuntu下vscode无法连接Codex插件:403 Forbidden排查与TaoToken配置
2026/10/2 12:21:14
初学 Python 的学生写计算器,第一版通常长这样:
a=float(input("第一个数:"))op=input("运算符:")b=float(input("第二个数:"))ifop=="+":print(a+b)elifop=="-":print(a-b)elifop=="*":print(a*b)elifop=="/":print(a/b)``` 这段代码能跑,但一碰就碎。输入 `abc` 会崩,除以 `0` 会崩,运算符打错会静默什么都不输出。计算器是最适合讲异常处理的例子:它的每一种错误都对应一个具体的、孩子能亲眼看到的崩溃现场,不需要抽象地解释“什么是异常”。## 完整代码下面这版可以直接运行,保存为 `calc.py`: ```pythondefcalc(a,op,b):"""执行一次运算,遇到问题抛出异常"""ifop=="+":returna+bifop=="-":returna-bifop=="*":returna*bifop=="/":ifb==0:raiseZeroDivisionError("除数不能为 0")returna/braiseValueError(f"不支持的运算符:{op}")defread_number(prompt):"""反复要求输入,直到拿到一个合法数字"""whileTrue:text=input(prompt).strip()try:returnfloat(text)exceptValueError:print(f" '{text}' 不是数字,请重新输入")defmain():print("简易计算器,输入 q 退出")whileTrue:first=input("\n第一个数(或 q 退出):").strip()iffirst.lower()=="q":print("已退出")breaktry:a=float(first)exceptValueError:print(f" '{first}' 不是数字,请重新输入")continueop=input("运算符(+ - * /):").strip()b=read_number("第二个数:")try:result=calc(a,op,b)exceptZeroDivisionErrorase:print(f" 计算失败:{e}")exceptValueErrorase:print(f" 计算失败:{e}")else:print(f" 结果:{a}{op}{b}={result}")if__name__=="__main__":main()```## 代码要点拆解**1.把运算逻辑和输入输出分开。**`calc()` 只负责算,不负责打印、不负责读输入。这样做的好处是异常有明确的“抛出点”:参数不对,`calc()` 直接 `raise`,调用者必须处理。如果运算和输入揉在一个函数里,异常到底该在哪一层捕获就说不清了。**2.主动 `raise` 比被动崩溃更好。**`1/0` 本身就会抛 `ZeroDivisionError`,但代码里仍然显式写了一遍: ```pythonifb==0:raiseZeroDivisionError("除数不能为 0")``` 目的是把“除数为0是非法输入”这个业务规则写进代码里。Python 默认的报错信息是 `division by zero`,而这里换成中文提示,面向用户更友好。学生也能借此理解:`raise` 就是自己造一个异常。**3.`try/except/else` 的 `else` 分支。**很多教材只讲 `try` 和 `except`。这里的 `else` 表示“`try` 里没有出错才执行”,把打印结果的代码放进去,语义上比全塞在 `try` 里更清晰:`try` 块只放可能出错的那一行。**4.`read_number()` 里的 `whileTrue`+`try`。**这是输入校验最经典的写法:拿到合法值就 `return` 跳出循环,不合法就打印提示继续循环。比套两层 `if` 判断字符串格式要简洁得多。## 学生常见错误**错误一:用 `except:` 一把抓。**```pythontry:result=a/bexcept:print("出错了")``` 裸 `except` 会吞掉所有异常,包括 `KeyboardInterrupt`(Ctrl+C),程序可能变得无法中断,调试时也看不到真实错误位置。至少要写成 `exceptZeroDivisionError:`,捕获自己预期的那一种。**错误二:把整个 `main` 包进一个 `try`。**```pythontry:a=float(input())b=float(input())print(a/b)exceptValueError:print("输入错误")exceptZeroDivisionError:print("除数为零")``` 逻辑上能跑,但一旦出错就无法判断是第一个数错了还是第二个数错了,用户只能从头再来。异常处理的范围要尽量小,精准到具体那一行。**错误三:认为 `float("1e3")` 会报错。**它不会,`float` 支持科学计数法,结果是 `1000.0`。同理 `float("inf")`、`float("nan")` 也是合法的。如果作业要求“只接受普通数字”,需要额外判断 `math.isfinite()`,这一点可以留作拓展。**错误四:`continue` 和 `break` 用混。**在 `main` 的第一个数校验里,输入非法必须 `continue`,否则会继续往下执行 `input("运算符")`,把一次错误输入变成两次提问。建议让学生自己在纸上画出循环走向。## 可以留的练习1.增加 `**` 幂运算和 `%` 取余,注意 `0**-1` 也会抛 `ZeroDivisionError`,验证一下。2.2.把 `main` 的两个 `except` 合并成 `except(ZeroDivisionError,ValueError)ase:`,观察行为是否一致。3.3.增加 `finally` 分支,在每次循环结束时打印一行分隔线,理解 `finally` 的执行时机。4.4.让 `calc()` 支持字符串表达式(如 `"1+2"`),用 `split()` 拆分,拆分失败时抛自定义异常。## 小结异常处理不是“加个try就完事”,它包含三个判断:哪里可能出错、出错后谁能处理、处理后是继续还是退出。计算器项目小,但把 `raise`、`try/except/else`、`whileTrue` 输入循环、异常捕获范围这几个点全串起来了。让学生先写崩溃版,再一步步改到健壮版,比直接给完整代码更能记住每种异常对应的现场。