5 道练习题·预计 40 分钟·做对一题解锁下一段
写代码这件事,最让新手崩溃的瞬间是哪种?想象一下:你刚学完语法,兴冲冲写了几十行代码,按下回车,结果终端弹出一坨红字:
Traceback (most recent call last):
File "main.py", line 5, in <module>
print(10 / 0)
ZeroDivisionError: division by zero
一脸懵。这玩意儿是啥?我哪里写错了?为啥程序就崩了?
其实啊,这就是 Python 的「异常机制」在工作。程序遇到了它处理不了的情况,比如除以零、读不存在的文件、把字符串当数字加,于是它就「抛」一个异常出来,整个程序停下来,告诉你:「我不干了,你来收拾」。
可是真实世界里的程序怎么可能因为一个小问题就停摆?银行 ATM 你输错密码三次它会提示,不会直接死机;网页加载图片失败会显示一个占位图,不会整页白屏;微信收消息网络不通它会重试,不会闪退。这些场景背后,全都是「异常处理」在做事。
我们先从最简单的例子开始:
print(10 / 0)输出:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
这就叫「异常」。Python 在执行 10 / 0 的时候发现:除数是零,这事儿数学上没法干,于是它创建了一个 ZeroDivisionError 对象,把这个对象「抛」出来。如果没人接,这个异常就会一路冒泡到最外层,最后由 Python 解释器接住,打印 traceback,然后退出程序。
再看几个:
nums = [1, 2, 3]
print(nums[10])
# IndexError: list index out of range
d = {'name': '小明'}
print(d['age'])
# KeyError: 'age'每一种「错误」都有它自己的名字。这些名字就是异常的「类型」,是 Python 内置的一组类。它们不是给你看着玩的,是供你用来「精确捕捉」的——不同类型用不同的处理方式。
Python 早就给我们准备好了一整套工具:
try / except:基本捕获结构else / finally:完整四件套raise:主动抛出异常学完这一节,再也不怕红字 traceback。
把第一段代码改造一下。我们不希望除以零让整个程序崩溃,而是希望它在崩之前给出一句友好的提示,然后继续往下走:
try:
result = 10 / 0
print(result)
except ZeroDivisionError:
print('哎呀,除数不能是零')
print('程序继续运行')输出:
哎呀,除数不能是零
程序继续运行
是不是发现,红字 traceback 没了,程序也没崩,最后那句「程序继续运行」也乖乖打印出来了。
try / except 的语法就这么简单,记住三件事:
try: 块里放「可能出问题」的代码except XxxError: 块里放「出了问题该怎么办」的代码try 块没出错,except 块完全跳过,跟没写一样如果 try 块里有十行代码,第三行炸了,后面七行还会执行吗?
答案是:不会。Python 一旦在 try 里发现异常,就立刻跳到对应的 except,try 里剩下的代码全部跳过。我们写个例子验证一下:
try:
print('第一行')
print(10 / 0)
print('第三行——这一行不会被执行')
except ZeroDivisionError:
print('我接住了')
print('程序继续')输出:
第一行
我接住了
程序继续
果然,「第三行」没打印出来。这个细节非常重要,很多新手 debug 半天找不到问题,就是因为以为 try 里抛了异常之后下面还会跑——不会的,跳过了。
请写一个函数 safe_divide(a, b):
a / bb 是 0,捕获 ZeroDivisionError,打印 '除数不能是零',然后返回 None然后调用:
print(safe_divide(10, 2))
print(safe_divide(10, 0))
输出应该是:
5.0
除数不能是零
None
注意 safe_divide(10, 0) 因为返回 None,外层 print 会打印 None。