在Python的'with'语句中捕获异常
我搞不清楚怎么处理Python中'with'语句的异常。如果我有一段代码:
with open("a.txt") as f:
print f.readlines()
我真的想处理“找不到文件”的异常,以便可以做点什么。但是我不能写
with open("a.txt") as f:
print f.readlines()
except:
print 'oops'
也不能写
with open("a.txt") as f:
print f.readlines()
else:
print 'oops'
把with
放在try/except语句里也不管用,异常没有被抛出。我该怎么做才能以Python的方式在with
语句中处理失败呢?
6 个回答
82
在使用Python的'with'语句时捕获异常
'with'语句从Python 2.6开始就可以使用,不需要额外的__future__
导入。其实在Python 2.5的时候就可以用这个功能了(不过现在是时候升级了!)
from __future__ import with_statement
你现在的代码离正确只差一步,但with
语句本身并没有except
这个部分:
with open("a.txt") as f: print(f.readlines()) except: # <- with doesn't have an except clause. print('oops')
上下文管理器的__exit__
方法,如果返回False
,在结束时会重新抛出错误。如果返回True
,则会抑制这个错误。内置的open
函数的__exit__
方法不会返回True
,所以你需要把它放在一个try和except的代码块里:
try:
with open("a.txt") as f:
print(f.readlines())
except Exception as error:
print('oops')
还有一点标准的注意事项:不要使用裸except:
,因为它会捕获BaseException
以及所有其他可能的异常和警告。至少要具体到Exception
,对于这个错误,可能需要捕获IOError
。只捕获你准备好处理的错误。
所以在这种情况下,你可以这样做:
>>> try:
... with open("a.txt") as f:
... print(f.readlines())
... except IOError as error:
... print('oops')
...
oops
107
最“Pythonic”的做法是利用with
语句,这在PEP 343的示例#6中有介绍,里面讲了这个语句的背景。
from contextlib import contextmanager
@contextmanager
def opened_w_error(filename, mode="r"):
try:
f = open(filename, mode)
except IOError, err:
yield None, err
else:
try:
yield f, None
finally:
f.close()
用法如下:
with opened_w_error("/etc/passwd", "a") as (f, err):
if err:
print "IOError:", err
else:
f.write("guido::0:0::/:/bin/sh\n")
350
这个解决方案会把 with 块中的代码放在 try-except 语句之外。
try:
f = open('foo.txt')
except FileNotFoundError:
print('error')
else:
with f:
print f.readlines()