先看这段python代码:
# 第1段代码
mydata = []
out = open('myfile.txt', 'w+')
mydata.append('score')
mydata.append(99)
print(mydata, file = out)
out.close()
这段代码有个问题:当open
或append
失败时,将导致程序崩溃,而这不是我们期望。
我们需要运用到python的异常机制(try ... except ...
),可能我们会写这样的代码
# 第2段代码
try:
mydata = []
out = open('myfile.txt', 'w+')
mydata.append('score')
mydata.append(99)
print(mydata, file = out)
out.close()
except Exception as e :
print( e )
上面这个代码已经不会因为open
或 append
的失败而导致程序崩溃,但是还有一个问题,那就是当异常发生时,out.close()
不会被执行,这将导致一个句柄的泄漏。
你可能会觉得一个句柄的泄漏没什么大不了的,系统有足够的句柄。这句话对于一个小程序来说有些道理,但是考虑到一个复杂的软件系统而且这个系统可能终年不会被重启,那这样的小泄漏就很严重了。况且,我们应该尽可能追求完美的程序质量。
这个场景催生了另外一个异常处理的结构 try ... except ... finally
,代码可能这样:
# 第3段代码
try:
mydata = []
out = open('myfile.txt', 'w+')
mydata.append('score')
mydata.append(99)
print(mydata, file = out)
except Exception as e :
print( e )
finally:
out.close()
上面这段代码看似没有问题了,但还隐含了另一个逻辑错误,即:当 open('myfile.txt', 'w+')
失败时,finally:
中的 out.close()
将产生异常,因为out此时是无效的。所以,在关闭out这个句柄时,还需要判断这个其是否有效。可利用内置函数locals 进行判断,具体代码如下:
# 第4段代码
try:
mydata = []
out = open('noexisting.txt')
mydata.append('score')
mydata.append(99)
print(mydata, file = out)
except Exception as e :
print( e )
finally:
if 'out' in locals() : # 判断'out'是否在局部变量列表里面
out.close();
到这里,这段代码已经是可用的代码了。
值得一提的是,python提供了 with
语法,自动回收已打开的文件,所以可以有以下这个更简洁的版本:
try:
with open('noexisting.txt') as out :
mydata.append('score')
mydata.append(99)
except Exception as e :
print( e )