我写这个例子是为了向自己展示当发生异常时 __exit__
没有运行:
class A(object):
def __enter__(self):
print('enter')
def __exit__(self):
print('exit')
try:
with A() as a:
raise RunTimeError()
except Exception as e:
print('except')
输出:
enter
except
也就是说,使用 with
语句并捕获异常,同时确保 __exit__
最终运行的正确方法是什么?
谢谢!
调用 __exit__
函数,无论 with
主体是否引发错误。您的函数需要有额外的参数 exc_type
(异常的类型)、exc_value
(异常对象)和 traceback
(异常的回溯)生成)。
如果 with
主体没有引发错误
,则三个参数为无
。如果出现错误,它们将采用上述值。
但是你可以关闭一个文件,不管是否有错误,然后再处理错误。
所以我们可以在这里实现它,例如:
class A(object):
def __enter__(self):
<b>self.file = open('some_file.txt')</b>
<b>return self.file</b>
def __exit__(self<b>, exc_type, exc_value, traceback</b>):
<b>print(('exit', exc_type, exc_value, traceback))</b>
# close the file, regardless of exceptions
<b>self.file.close()</b>
<b>return False</b> # silence the exception?
如果我们现在这样写:
with A():
raise Exception
我们将获得异常,__exit__
函数将打印:
('exit', <class 'Exception'>, Exception(), <traceback object at 0x7fc512c924c8>)
我们可以检查异常类、异常值和回溯,并进行相应的处理。例如,基于异常,我们可能决定关闭文件、发送错误报告、中止 SQL 事务。
__exit__
函数也有一个返回值(如果没有指定,Python 函数返回None
)。如果 __exit__
函数返回一个具有truthiness True
的对象,它将抑制异常:异常不会从 with
block 中提出。否则它将从 with
block 中提出。例如在我们的示例中,我们仍然收到异常。
class SilenceExceptions(object):
def __enter__(self):
pass
def __exit__(self<b>, exc_type, exc_value, traceback</b>):
<b>return True</b> # silence ALL exceptions
如果我们现在调用:
with SilenceExceptions():
raise Error
我们不会看到异常,因为它在 __exit__
函数中被“捕获”。