这是本书中使用的fileinfo.py
小片段。这是打开一个MP3文件并读取最后128个字节以获取并稍后解析元数据。
try:
fsock = open(filename, "rb", 0)
try:
fsock.seek(-128, 2)
tagdata = fsock.read(128)
finally:
fsock.close()
.
. # process tagdata: will NEVER raise IOError though
.
except IOError:
pass
这可以重构为:
try:
fsock = open(filename, "rb", 0)
try:
fsock.seek(-128, 2)
tagdata = fsock.read(128)
except IOError:
pass
finally:
fsock.close()
.
. # process tagdata
.
在我学习Java
时,我甚至习惯了这个问题。我们是否应该保留可以在try..except
块内实际引发异常的逻辑,或者为了保持在一个地方执行某项特定工作的代码;保留其他代码,不会在try...except
?
答案 0 :(得分:6)
最常被接受的标准是尽可能少地将代码放在try..except中。推理是,如果尝试了大量代码,你就不知道其他代码将会引发什么然后它变得非常混乱。
您可以在PEP 8中看到许多优秀的样式信息,其中包括:
- Additionally, for all try/except clauses, limit the 'try' clause
to the absolute minimum amount of code necessary. Again, this
avoids masking bugs.
Yes:
try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
No:
try:
# Too broad!
return handle_value(collection[key])
except KeyError:
# Will also catch KeyError raised by handle_value()
return key_not_found(key)
答案 1 :(得分:6)
try
/ finally
子句的主要目的是关闭文件而不管发生了什么,将其移到外部try
/ except
是没有意义的我假设你正在努力做到:
try:
fsock = open(filename, "rb", 0)
try:
fsock.seek(-128, 2)
tagdata = fsock.read(128)
except:
pass
except IOError:
pass
finally:
fsock.close()
原因是,如果实际提出IOError
,则调用fsock.close()
会引发另一个异常,因为不会分配fsock
。而不是其中之一,最好使用with
语句,它将自动为您关闭文件:
try:
with open(filename, 'rb') as fsock:
fsock.seek(-128, 2)
tagdata = fsock.read(128)
except IOError:
pass
答案 2 :(得分:1)
第二段代码在语法上是无效的,所以你应该更喜欢第一种形式。
如果你通过添加except
或finally
子句使它在语法上有效,那么它在语义上是无效的:如果open
失败,你仍然会尝试关闭fsock
,不会被分配。
答案 3 :(得分:0)
如果open
失败,则您无法分配到tagdata
,因此您不应允许代码到达处理tagdata
的位置。通常,处理此问题的最佳方法是在更高级别处理IOError
(即将其包装在函数中并在调用上下文中处理它)。
finally
来做这类事情 - 我们有一个更强大的习惯用法。我们还有一个else
子句,可以附加到try / except块,只有在异常处理程序不被调用时才会执行。
所以我们得到类似的东西:
def get_data():
with open(filename, "rb", 0) as fsock:
fsock.seek(-128, 2)
return fsock.read(128)
def do_processing():
try: tagdata = get_data()
except IOError: handle_error()
else: process(tagdata)