本片笔记学习自:Write Cleaner Python: Use Exceptions
当我说使用异常,我并不是说在你的包中创建一些异常类,然后在每个可能的地方都抛出异常。我想说尽量利用Python内建的异常。事实上,你的代码到处都有异常机制在工作。
- for循环是怎么工作的?
words = ['exceptions', 'are', 'useful']
for word in words:
print(word)
for循环怎么知道什么时候结束呢?在迭代器结束的时候,迭代器会抛出StopIteration异常,
- 为什么使用异常?
for循环显然可以不用异常来实现,那为什么要用异常?因为python所采用的检查错误的哲学。
如果不使用异常,我们在事情之前首先要检查条件是否都符合再执行。如果你不仔细检查所有可能的错误,灾难就发生了。考虑以下代码:
def print_object(some_object):
# Check if the object is printable...
if isinstance(some_object, str):
print(some_object)
elif isinstance(some_object, dict):
print(some_object)
elif isinstance(some_object, list):
print(some_object)
# 97 elifs later...
else:
print("unprintable object")
想要提前预料所有错误状况注定要失败。
如果使用异常,我们可以写成下面的代码:
def print_object(some_object):
# Check if the object is printable...
try:
printable = str(some_object)
print(printable)
except TypeError:
print("unprintable object")
- 更多使用情况
else的使用:在没有异常抛出的时候执行。下面的代码同时也修正了上面代码可能存在的一个bug,就是可能是print导致的异常而不是str强制类型转化导致的。else里面也经常用来放一些收尾工作的代码,比如关闭数据库等等。
def print_object(some_object):
# Check if the object is printable...
try:
printable = str(some_object)
except TypeError:
print("unprintable object")
else:
print(printable)
raise的使用:通常raise用来抛出异常,但是在我们处理异常的时候,我们也可以做一些事情,然后继续把原来的异常继续抛上去,这让上层应用可以知道异常的来源,而如果我们在处理异常的时候重新抛出一个异常,这就会让上层应用不知道真正的异常来自哪里。
上面两种处理异常的情况,也就是if提前判断和使用异常,这两个方法分别是Look Before You Leap (LBYL) and Easier to Ask for Forgiveness than Permission,后者是尽管去做事情,如果出现异常,处理它。
- 异常的代价
异常也损失一些性能,但是在python中代价很小。