8.5 异常之禅
异常处理并不是很复杂。如果你知道代码可能引发某种异常,且不希望出现这种异常时程序终止并显示栈跟踪消息,可添加必要的try/except或try/finally语句(或结合使用)来处理它。
有时候,可使用条件语句来达成异常处理实现的目标,但这样编写出来的代码可能不那么自然,可读性也没那么高。另一方面,有些任务使用if/else完成时看似很自然,但实际上使用try/except来完成要好得多。下面来看两个示例。
假设有一个字典,你要在指定的键存在时打印与之相关联的值,否则什么都不做。实现这种功能的代码可能类似于下面这样:
def describe_person(person):
print('Description of', person['name'])
print('Age:', person['age'])
if 'occupation' in person:
print('Occupation:', person['occupation'])
如果你调用这个函数,并向它提供一个包含姓名Throatwobbler Mangrove和年龄42(但不包含职业)的字典,输出将如下:
Description of Throatwobbler Mangrove
Age: 42
如果你在这个字典中添加职业camper,输出将如下:
Description of Throatwobbler Mangrove
Age: 42
Occupation: camper
这段代码很直观,但效率不高(虽然这里的重点是代码简洁),因为它必须两次查找'occupation'键:一次检查这个键是否存在(在条件中),另一次获取这个键关联的值,以便将其打印出来。下面是另一种解决方案:
def describe_person(person):
print('Description of', person['name'])
print('Age:', person['age'])
try:
print('Occupation:', person['occupation'])
except KeyError:
pass
在这里,函数直接假设存在'occupation'键。如果这种假设正确,就能省点事:直接获取并打印值,而无需检查这个键是否存在。如果这个键不存在,将引发KeyError异常,而except子句将捕获这个异常。
你可能发现,检查对象是否包含特定的属性时, try/except也很有用。例如,假设你要检查一个对象是否包含属性write,可使用类似于下面的代码:
try:
obj.write
except AttributeError:
print('The object is not writeable')
else:
print('The object is writeable')
在这里, try子句只是访问属性write, 而没有使用它来做任何事情。如果引发了AttributeError异常,说明对象没有属性write,否则就说明有这个属性。这种解决方案可替代7.2.9节介绍的使用getattr的解决方案,而且更自然。具体使用哪种解决方案,在很大程度上取决于个人喜好。
请注意,这里在效率方面的提高并不大(实际上是微乎其微)。一般而言,除非程序存在性能方面的问题,否则不应过多考虑这样的优化。关键是在很多情况下,相比于使用if/else,使用try/except语句更自然,也更符合Python的风格。因此你应养成尽可能使用try/except语句的习惯
领取专属 10元无门槛券
私享最新 技术干货