在try/except/else/finally中受益
在Python
中,有四种可能的情况你要在产生异常的时候采取行动。这些异常可以被try
,except
,else
,finally
块自动的捕获。在复合语句中,每一个块都服务着一个独特的目标,并且它们的组合语句也很有用(详见第51
项:又如,“从API
中定义一个根异常来隔离调用者”)。
finally
块
当你想使得异常传播的时候可以使用try/finally
,但是你还想在代码出现异常的时候仍然能够整洁的运行。一个通用的使用方式就是在try/finally
块中可靠的关闭文件处理句柄(详见第43项:对另一个方法而言“为了可重复的使用try/finally
,考虑一下contextlib
和with
语句)。
# 此处可能引发IO异常
handle = open('/tmp/random_data.txt')
try:
# 可能引发UnicodeDEcode异常
data = handle.read()
finally:
# 总是在try语句结束后关闭文件
handle.close()
由于读文件而引发的异常总是会被抛到调用方代码处,而为保证finally
块中的文件操作能被正确的关闭。你必须在try
块之前调用open
方法,因为这样如果文件不存在会引发IOError
,使得能跳过finally
块而不会导致代码本身存在逻辑问题。
else
块
使用try/except/else
块可以使得代码中对哪种一场要被处理,哪种异常要往上抛出的处理变得更加清晰。当try
块内的代码没有引发异常的时候,else
块就会得到执行。else
块可以使得try
块中的代码变得更加的简短,并且大大改善代码的可读性。例如:你可能想从一个字符串中加载JSON
字典数据,并且返回类似于键值对信息的结果。
def load_json_key(data, key):
try:
result_dict = json.loads(data) # 可能引发ValueError异常
except ValueError as e:
raise KeyError from e
else:
return result_dict[key] # 可能引发KeyError
如果字符串中包含的数据不是合法的JSON
串数据,解码函数json.loads
将会引发一个ValueError
异常,然后被except
块捕获并且处理。如果解码工作可以正常的得到执行,那么在else
块中寻找key
对应的值的时候就很有可能引发KeyError
异常。然后这个一场将会被上抛给调用该函数的代码,因为它们是try
块之外的外部代码。else
块的存在可以确保try/except
块可以处理,分辨的异常有哪些。这使得异常要抛给谁,变得更加的清晰。
大综合
综合性的使用就是把try/else/except/finally
都用上,写到一个复合语句中。例如:你想读取一个描述了工作信息的文件,然后处理,再更新到这个文件中。这里,try
块就经常的被用于读取文件和处理文件,except
块用于处理从try
块中捕获到的预期的异常,而else
块则习惯用于更新文件内部的信息并且允许相关的异常往上抛出,最后finally
块用于关闭文件等打扫战场性质的工作。
UNDEFINED = object()
def divide_json(path):
handle = open(path,'r+') # 可能抛出IOError异常
try:
data = handle.read() # 可能引发UnicodeDecodeError异常
op = json.loads(data) # 可能引发ValueError异常
value = (
op['numeerator'] / # 这里是除号!
op['denominator'] # 可能引发ZeroDivisionError异常
except ZeroDivisionError as e:
return UNDEFINED
else:
op['result'] = value
result = json.dumps(op)
handle.seek(0)
handle.write(result) # 可能引发IOError异常
return value
finally:
handle.close() # 肯定能够被执行成功
这样的结构是非常非常实用而且好用的,因为所有的块都能以直观的方法一起工作。例如: 如果一个在else
快中写文件数据的时候发生了,finally
块仍然会正确的关闭文件,减少了文件损坏的可能。
备忘录
try/finally
组合语句可以使得你的代码变得很整洁而无视try
块中是否发生异常。else
块可以最大限度的减少try
块中的代码的长度,并且可以可视化地辨别try/except
成功运行的部分。else
块经常会被用于在try
块成功运行后添加额外的行为,但是要确保代码会在finally
块之前得到运行。