2.25. 错误处理¶
Python 中大多数运行时问题都以异常的形式表现出来 —— 这是一种有名称、有结构的方式,用来报告出了某种问题。ValueError、TypeError、KeyError、OSError、MemoryError 都是例子;每一个都是一个类,而抛出一个异常会停止当前调用,并在周围的代码中寻找处理程序。
2.25.1. try / except¶
用 try 包裹一段代码,以捕获它抛出的任何异常:
try:
n = int(input_text)
except ValueError:
n = 0
如果 int(...) 转换失败,控制流会跳转到 except 块,而不会让错误进一步向外传播。如果 input_text 是一个有效的整数字符串,except 块就会被跳过。
单个 try 可以带多个 except 块,每个捕获不同类型的错误:
try:
value = data[key]
except KeyError:
value = None
except TypeError:
value = -1
Python 按顺序匹配;第一个其异常类匹配的块来处理该问题。捕获 Exception(几乎所有异常的基类)会处理任何错误;请把这种做法留给程序的最外层,因为那里的替代方案就是崩溃。
警告
一个裸 except:(关键字后面没有类)也会捕获 KeyboardInterrupt —— 即当你按下 IDE 的停止按钮中断正在运行的脚本时,IDE 所发送的异常。一个被裸 except: pass 包裹的循环会吞掉这个中断并继续运行,使得除了断电重启之外没有任何办法停止脚本。
当你确实需要广泛捕获时,请优先使用 except Exception: 而非裸 except:。KeyboardInterrupt 继承自 BaseException 而非 Exception,因此 except Exception: 会让停止按钮仍然有效。
2.25.1.1. 检查异常¶
要读取附加在异常上的消息,用 as 给它命名:
try:
f = open("data.txt")
except OSError as e:
print("could not open file:", e)
由 as 绑定的变量只在 except 块内部有效。
2.25.2. else 和 finally¶
try 块有两个可选的附加部分。
else 仅在 try 顺利完成而未抛出异常时才运行:
try:
value = compute()
except ValueError:
print("bad input")
else:
print("got", value)
把“成功时该做什么”放进 else 可以让 try 块保持简短 —— 只有那行可能失败的代码才应该放在 try 里。
finally 会在最后无论如何都运行 —— 无论 try 是成功了、抛出后被处理了,还是抛出后即将向外传播:
try:
do_work()
finally:
cleanup()
finally 总会运行。else 只在没有异常的那条路径上运行。¶
对于大多数获取/释放模式,请优先使用 上下文管理器 而非 try / finally 组合 —— 资源本身会管理自己的清理。
2.25.3. 常见的内置异常¶
下面是你会经常遇到的异常的简短清单:
ValueError—— 类型正确,值错误(bytes([300])—— 300 是正确的类型,但超出了 0..255 的有效字节范围)。TypeError—— 类型完全不对(len(42))。IndexError—— 索引越过了序列的末尾。AttributeError—— 访问一个不存在的属性("abc".foo)。OSError—— 文件系统或 I/O 故障。MemoryError—— 堆内存耗尽。在内存受限的运行时上,这可能在正常运行期间发生 —— 而不仅仅是在极端情况下。