如何控制异常 try-except

如何控制异常 try-except

作者: 莫烦 编辑: 莫烦 发布于: 2021-05-12

出错我们无可避免,代码写错程序当然运行不了。但是即使你代码写对了,你就一定能保证运行成功吗? 当然不是,大千世界,这世界复杂到你处理不过来。如果这个代码完全是你自己写的, 而且确保每个环节都检测到了。那有可能你不会运行出任何错误。 但是这代码你有可能是基于他人的代码,别人没有你这样敬业,他的代码可能会出错呀。

即使别人的代码不出错,但是也有可能物理环境会出错呀,比如 CPU 超了,某人的服务运行失败,你恰好又是基于他提供的服务, 你也跟着超时了。这些都会让你的程序报错。

还好,在 Python 中,或者任何语言中,都有一些处理错误的方式,handle 这些错误,保证你的程序可以顺利执行下去。

我知道你可能报错

为了让你的程序兼容性更好,你往往就得考虑对潜在的错误进行捕捉。而在我们假设的文件管理系统里, 文件的处理也会经常有无可避免的错误。比如我读了一个不存在的文件。

这时我们来观察一下,在它的报错中有这样一个关键词 FileNotFoundError,这就是我们要处理的异常类型。 那么开始动手捕捉这个错误,并处理它吧。

你运行一下,发现现在已经没有报错了吧,因为潜在的 FileNotFoundError 这个异常已经被 except 给捕捉了起来。 而且捕捉后,我们还进行了一个创建文件并写入文本的工作。当你再点击上面的运行,你会发现重复执行这段代码的话,他就可以正常打印文字到终端了。

处理多个异常

如果我的程序在执行某个功能的时候可能会报多种不同的异常,我应该怎么办呢?上面我们处理的都是一种异常,下面我们就用另一种方法来处理多种异常。 首先如果你的多种异常的处理方案是一样的话,我们就能在 except 这里多写几种异常种类。 它会按照我们正常的执行顺序,依次检测异常,报出第一个遇到的异常。

上面这个案例,如果你在原本的 d 中加上一个 gender, 让 KeyError 不报出来,它就会接着报字典的 IndexError 异常了。

如果我想让两种 error 分开来处理,比如没有 key 的时候,加一个 key,没有 index 的时候加一个 index。能行吗?那就写两个 except 吧。

但是你有没有发现一个小事情,它不会同时处理字典的 KeyError 和列表的 IndexError,因为在程序顺序执行的时候,只要是报错了, 那么就会终止错误之后的代码,进入错误 回收 环节。这个回收环节在上面的案例中也就是 except 的错误处理环节。 所以你就能发现,其实在你不改动上面代码的情况下,l 列表是没有 append(4) 的。只有当字典正常的时候,列表的报错才会触发。

try-except-else

还有一个 try-except-else 的模式,在 else 中处理没有报错的情况,我们对比下面两种写法,一种让它报错,一种不让它报错。 下面的代码,是会报错的代码,我们看到它不会进入到 else

下面的代码,我们把 l 加一个位置,就不会报错了,那么代码就会执行到 else 阶段。

try-except-finally

你已经见识了大部分的异常处理方法了。如果 else 是为了执行没有异常的状况,那么 finally 就是为了执行 不管有没有异常 的情况。 无论有报错还是没报错,finally 下面的代码都会运行。下面第一段代码是会报错的,第二段不会报错。

上面这两种模式主要用在什么 case 当中呢?你想一下,是不是有些时候,不管你有没有报错,你都想让程序去执行什么。我们甚至都不需要为任何异常做任何处理。 这种时候,也就是说,你有异常吧,我不让你终止主程序,你没有异常吧,万事大吉。

raise手动触发异常

有天我被调去了做开源库的工作,为了别人使用到我的代码时不至于骂街,或者异常后报出一大堆很难 debug 的信息。 这个时候我就该考虑考虑 raise 的用法了。 为什么这么说?因为 raise 是你为别人犯错留下的证据,或者是告诉别人你怎么犯错的。这个信息对于别人 dubug 你的代码十分有好处。

另一种情况是,你写了成百上千行代码,你也不能全记住代码的每一个细节。所以一旦报错,你也需要一个友善的错误信息提示,这时用 raise 准没错。

在现在的 IT 互联网时代,我们的程序服务很多都发生在网上,通过网络传输后计算数据。在这种情况下,raise 一个可能发生的错误十分有用。 另外,如果你已经是 Python 玩家了,你在使用其他库的时候肯定遇到过很多报错的情况,这就是别人用上面那种用法告诉你出什么错了。 所以当你为别人提供功能时,你就要学会用 raise。

Python异常错误名称表

有哪些能被 raise 的 error 呢?下面我们就列一个表告诉你~

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

异常千变万化,告知他人犯了什么错,为别人留下充足的信息,帮助别人找到正确的使用方法吧~


降低知识传递的门槛

莫烦经常从互联网上学习知识,开源分享的人是我学习的榜样。 他们的行为也改变了我对教育的态度: 降低知识传递的门槛

我组建了微信群,欢迎大家加入,交流经验,提出问题,互相帮持。 扫码后,请一定备注"莫烦",否则我不会同意你的入群申请。

wechat