「异常」处理的时候,你用过这些技巧吗?

时间:2022-06-23
本文章向大家介绍「异常」处理的时候,你用过这些技巧吗?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

00.写在之前

当 Python 检测到一个错误时,解释器就无法继续执行下去,于是抛出提示信息,即为「异常」。程序出现了异常,就要做「异常处理」。

Python 的异常在使用上很简单,因此很多人处理异常的时候也相当简单粗暴,随着性子用 try...except...,心情好了可能带上 else 或者 finally,感觉差不多就行,完全不考虑之后会不会再有其它的异常或者某些玄学的事情发生。

「异常」背后是有很多技巧存在的,并不是想象中的随感觉乱用,接下来我就分享一下我所知道的技巧,让你在碰到异常的时候能得心应手的处理。

01.except 技巧

使用 Python 可以选择捕获哪些异常,在这里必须要注意的是不要涵盖的范围太广,即要尽量避免 except 后面为空,最好是要带东西的。except 后面如果什么也不带,它会捕捉 try 代码块中代码执行时所出现的每个异常。

虽然后面什么也不带在大多数情况下得到的也是我们想要的结果,但是代码块中如果是个嵌套结构的话,它可能会破坏嵌套结构中的 try 得到它想要的结果。比如下面这种情况:

def func():
 try:
 # do something1
 except:
 # do something2

try:
 func()
except NameError:
 # do something3

比如上面的代码,如果在 something1 处出现了 NameError,那么所有的异常都会被 something2 处捕获到,程序就此停掉,而正常情况下应该捕获到 NameError 的 something3 处则什么异常也没有。

上面只是说了一个简单的情况,因为 Python 运行在个人电脑中,可能有时候内存错误,系统莫名退出这种异常也会被捕捉到,而现实情况是这些和我们当前的运行的程序一毛钱关系也没有。

可能这时候有人会想到 Exception 这个内置异常类,但实际情况是 except Exception 比 except 后面什么也不带好不到哪里去,大概也只是好在系统退出这种异常 Exception 不会捕捉。

那该如何使用 except 呢?

那就是尽量让 except 后面具体化,例如上面代码中的 except NameError: ,意图明确,不会拦截无关的事件。虽然只写一个 except 很方便,但有时候追求方便恰恰就是产生麻烦的源头。

02.类异常

在上一节我说尽量要让 except 后面具体化,在列出特定的异常时,就只是去捕捉实际列出来的事件。但是现在又有这么一个问题,当程序简单的时候还好说,但是随着程序变得复杂起来,肯定还会出现别的异常,这样的话我们就只能回头去找,然后再把新出现的异常加进去:

try:
 # do something1
except (NameError,KeyError):
 # do something2
else:
 # do something3

上面的代码中是把 NameError 和 KeyError 看作是正常的情况,把其它的视为错误。如果在之后的发展中增加了 TypeError ,程序就会把它视为错误并且对它进行处理,除非把它加进去:

try:
# do something1
except (NameError,KeyError,TypeError):
# do something2
else:
# do something3

但是这样每次过去添加也太麻烦了,当代码量巨大的时候,定位然后再添加是又费时又费力,所以这个时候我们可以使用「类异常」。类异常是由超类关系进行匹配,只要 except 子句列举了异常的类或其它超类名,出现的异常就会匹配这个子句:

class BaseError(Exception):
 # return all error
class IsNameError(BaseError):
 # return NameError
class IsKeyError(BaseError):
 # return KeyError

try:
 # do something1
except BaseError:
 # do something2
else:
 # do something3

当随着出现新的异常的时候,只需要再扩展响应的子类即可:

class BaseError(Exception):
 # return all error
class IsNameError(BaseError):
 # return NameError
class IsKeyError(BaseError):
 # return IsKeyError
class IsTypeError(BaseError):
 # return IsTypeError

try:
 # do something1
except BaseError:
 # do something2
else:
 # do something3

这样就不用再手动扩展 except 后面的异常列表,BaseError 变成了可扩展的异常分类。

以上。