在try-except块中使用python的"with"语句
这是使用Python的“with”语句和try-except块结合的正确方法吗?
try:
with open("file", "r") as f:
line = f.readline()
except IOError:
<whatever>
如果是的话,那考虑一下以前的做法:
try:
f = open("file", "r")
line = f.readline()
except IOError:
<whatever>
finally:
f.close()
在这里,“with”语句的主要好处是我们可以省掉三行代码吗?对我来说,这个理由似乎并不是特别有说服力在这个用例中(不过我明白“with”语句还有其他用法)。
编辑:上面这两个代码块的功能是一样的吗?
编辑2:前面的一些回答一般性地谈到了使用“with”的好处,但在这里似乎帮助不大。我们都已经(或者应该已经)显式地调用f.close()很多年了。我想一个好处是,写代码不太认真的人会从使用“with”中受益。
4 个回答
我觉得你对“with”语句的理解有点偏差,它并不仅仅是为了减少代码行数。
实际上,它还负责初始化和处理清理工作。
在你的例子中,“with”做了以下几件事:
- 打开一个文件,
- 处理文件的内容,
- 确保最后关闭这个文件。
这里有一个链接可以帮助你理解“with”语句: http://effbot.org/zone/python-with-statement.htm
补充一下:是的,你使用“with”的方式是正确的,两个代码块的功能是一样的。
关于为什么要使用“with”的问题?这是因为它带来的好处,比如你提到的可能会忘记写 f.close() 的情况。
如果finally
块里的内容是根据正在打开的文件对象的属性来决定的,那为什么不让文件对象的实现者来写这个finally
块呢?这就是使用with
语句的好处,远不止是在这个特定情况下节省三行代码。
而且,是的,你把with
和try-except
结合起来的方式几乎是唯一的做法,因为在open
语句本身引发的异常错误是无法在with
块内捕获的。
- 你给的两个代码块并不相同
- 你说的那种老方法有个严重的错误:如果打开文件失败,你会在
finally
部分遇到第二个异常,因为f
并没有被绑定。
等价的老式代码应该是:
try:
f = open("file", "r")
try:
line = f.readline()
finally:
f.close()
except IOError:
<whatever>
正如你所看到的,使用with
语句可以减少出错的机会。在更新版本的Python(2.7,3.1)中,你还可以在一个with
语句中组合多个表达式。例如:
with open("input", "r") as inp, open("output", "w") as out:
out.write(inp.read())
除此之外,我个人认为尽早捕获任何异常是一种坏习惯。这并不是异常的目的。如果可能失败的IO函数是更复杂操作的一部分,在大多数情况下,IO错误应该终止整个操作,因此应该在外层处理。使用with
语句,你可以摆脱所有这些内层的try...finally
语句。