来源:强哥 公众号:Python与数据分析 链接:
https://mp.weixin.qq.com/s/PU0-TwTABa1eC3BzxAzcbw
Python中的异常处理一般是如下的形式:
try:
except : # try中发生name1的异常时处理
except , : # try中发生name2, name3的异常时处理
except: # 其他异常发生时处理
else: # 没有异常发生时执行
finally: # 不管有没有异常发生都实行
在写异常处理的时候通常有以下两点建议
尽量定位具体的异常类型,不要使用单独的except处理所有异常
注意异常捕获的顺序
对于上面两点,下面分别举例说明。
尽量定位具体的异常类型,不要使用单独的except处理所有异常
这里我们定义一个Person的类,并实现两个方法,一个是 set_age 用于设置年龄,一个是 set_weight 用于设置体重。当设置年龄或者体重为负值是,程序抛出异常。代码如下
import sys
class InvalidAge(Exception):
pass
class InvalidWeight(Exception):
pass
class Person(object):
def __init__(self):
pass
def set_age(self, age):
if age <>0:
raise InvalidAge()
self.age = age
def set_weight(self, weight):
if weight <=>=>0:
raise InvalidWeight()
self.weight = weight
我们来看下下面的异常处理的代码
p = Person()
try:
p.set_age(30)
p.set_weight(-30)
except:
sys.exit('Age cannot be negative')
这段代码会输出
Age cannot be negative
这个输出会让我们以为是年龄设置出了问题,但实际上年龄的设置并没有问题,而是体重的设置出了问题。由于单独使用except语句,真实的错误被掩盖。
如果我们在用except捕获异常的时候使用更精确的异常类型定位,就可以避免这样的问题。如下
try:
p.set_age(30)
p.set_weight(-30)
except InvalidAge:
sys.exit('Age cannot be negative')
except InvalidWeight:
sys.exit('Weight cannot be negative')
输出:
Weight cannot be negative
使用单独的except会捕获所有的异常,给debug增加难度。如果在某些情况下不得不这样用,建议用raise向上层抛出异常。
注意异常捕获的顺序
Python的内建异常有一定的继承结构,如ZeroDivisionError继承自ArithmeticError,ArithmeticError继承自StandardError,StandardError继承自Exception,Exception继承自BaseException。
一般在捕获异常的时候建议先捕获子类的异常,后捕获父类的异常。这样,在有异常发生时,python解释器会根据except声明的顺序进行匹配,在第一个匹配的地方就立即处理异常。
我们修改一下前面的例子。定义一个异常类的基类InvalidValue,并且两个异常类InvalidAge和InvalidWeight都继承自InvalidValue类。如下
class InvalidValue(Exception):
pass
class InvalidAge(InvalidValue):
pass
class InvalidWeight(InvalidValue):
pass
修改异常处理部分的代码如下
p = Person()
try:
p.set_age(30)
p.set_weight(-30)
except InvalidValue:
sys.exit('Invalid value')
except InvalidAge:
sys.exit('Age cannot be negative')
except InvalidWeight:
sys.exit('Weight cannot be negative')
上面的例子会输出
Invalid value
这里InvalidWeight类继承自InvalidValue类,当抛出InvalidWeight异常的时候,由于它是InvalidValue的子类,在except InvalidValue处就被捕获了,输出了Invalid value的消息,而真正处理InvalidWeight异常的消息却被掩盖了。
改变一下异常捕获的顺序,把捕获子类的except语句放在捕获父类的except语句之前,就可以避免这样的问题。如下
p = Person()
try:
p.set_age(30)
p.set_weight(-30)
except InvalidAge:
sys.exit('Age cannot be negative')
except InvalidWeight:
sys.exit('Weight cannot be negative')
except InvalidValue:
sys.exit('Invalid value')
输出
Weight cannot be negative
可以看到,在写异常处理的时候注意以上两点,可以帮助我们更准确的定位异常类型,提高debug的效率。
(完)
看完本文有收获?请转发分享给更多人
关注「Python那些事」,做全栈开发工程师
联系客服