使用Python’with’语句时捕获异常

Catching an exception while using a Python 'with' statement

让我感到羞愧的是,我不知道如何处理python"with"语句的异常。如果我有代码:

1
2
with open("a.txt") as f:
    print f.readlines()

我真的想处理"找不到文件的异常"来做一些事情。但我不会写字

1
2
3
4
with open("a.txt") as f:
    print f.readlines()
except:
    print 'oops'

不能写

1
2
3
4
with open("a.txt") as f:
    print f.readlines()
else:
    print 'oops'

在try/except语句中封闭"with"不起作用,否则:不会引发异常。我该怎么做才能以一种Python般的方式处理"with"语句中的失败呢?


1
2
3
4
5
6
7
from __future__ import with_statement

try:
    with open("a.txt" ) as f :
        print f.readlines()
except EnvironmentError: # parent of IOError, OSError *and* WindowsError where available
    print 'oops'

如果希望对打开的调用与工作代码中的错误进行不同的处理,可以执行以下操作:

1
2
3
4
5
6
7
try:
    f = open('foo.txt')
except IOError:
    print('error')
else:
    with f:
        print f.readlines()


利用with语句,最好的"pythonic"方法列为PEP 343中的示例6,给出了语句的背景。

1
2
3
4
5
6
7
8
9
10
11
@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()

使用方法如下:

1
2
3
4
5
6
with opened_w_error("/etc/passwd","a") as (f, err):
    if err:
        print"IOError:", err
    else:
        f.write("guido::0:0::/:/bin/sh
"
)


Catching an exception while using a Python 'with' statement

自Python2.6以来,WITH语句在没有__future__导入的情况下可用。您可以早于python 2.5就获得它(但现在是升级的时候了!)用:

1
from __future__ import with_statement

这是你最需要改正的地方。你快到了,但是with没有except条款:

1
2
3
4
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,因此您只需要将其嵌套在一个尝试中,除了块:

1
2
3
4
5
try:
    with open("a.txt") as f:
        print(f.readlines())
except Exception as error:
    print('oops')

标准样板:不要使用裸露的except:,它可以捕获BaseException和其他可能的异常和警告。至少和Exception一样具体,对于这个错误,可能会捕获IOError。只捕获准备处理的错误。

所以在这种情况下,你应该这样做:

1
2
3
4
5
6
7
>>> try:
...     with open("a.txt") as f:
...         print(f.readlines())
... except IOError as error:
...     print('oops')
...
oops

采用标准异常处理

1
2
3
4
5
try:
    with open("a.txt") as f:
        #business as usual
except Exception as e:
    print"oops, handle exception:", e