re-raising an exception in a context handler
从上下文管理器上的datamodel文档:
Note that
__exit__() methods should not reraise the passed-in exception; this is the caller’s responsibility.
我有一个临时文件,其文件描述符我想用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Processor(object): ... def write(self, *args, **kwargs): if something_bad_happens: raise RuntimeError('This format expects %s columns: %s, got %s.' % ( (len(self.cols), self.cols, len(args)))) self.writer.writerow(args) def __enter__(self): return self def __exit__(self, type, value, traceback): # the RuntimeError from write will be set as type, value and so on .. # I'd like to close the stream here (release the file descriptor), # but I do not leave a trace of the associated file - # (one can always 'manually' delete with `os.remove` but maybe there's a # better way ..?) self.output_pipe.close() |
此外,我不希望在此特定情况下调用者中的错误处理有两个原因:
- 保持调用者中的代码最小化(见下文)
- 调用者对异常感到满意(快速失败就是我们想要的)
上下文管理器的用法如下:
1 2 3 4 5 6 7 8 9 | class Worker(object): ... def run(self): # output setup so it will emit a three column CSV with self.output().open('w') as output: output.write('John', 'CA', 92101) output.write('Jane', 'NY', 10304) # should yield an error, since only three 'columns' are allowed output.write('Hello', 'world') |
更新:我的问题有点不合理,因为我的问题真的归结为:在嵌套的上下文管理器中,如何将异常传递给最外层的CM?
-
当
__exit__ 返回True时,将吞下传递给它的任何异常。 -
当
__exit__ 返回False时,将重新启动该异常。
1 2 3 4 5 | def __exit__(self, type, value, traceback): self.output_pipe.close() # always close the file if type is not None: # an exception has occurred os.unlink(...) # remove the file return False # reraise the exception |
您当然可以省略
那么
1 | with self.output().open('w') as output: |
应该
1 | with self.output() as output: |
在任何情况下,如果你能安排后者是正确的语法会更好。您可能需要将
1 2 | def __enter__(self): return self.output_pipe.open('w') |
没有必要
测试是否没有例外:
1 2 3 | if type is None: # if no exception is raised, proceed as usual: self.output_pipe.close() |
如果您的上下文管理器在那一刻返回
请注意,