当尝试忽略上下文管理器执行期间引发的异常时,我有哪些选择?事实上,以下简单的上下文管理器只是传播结果,导致其结束执行,除非被捕获:
class contextMan:
def __enter__(self):
print("Entering Context")
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting Context")
if __name__ == "__main__":
with contextMan():
raise IndexError
Run Code Online (Sandbox Code Playgroud)
我当然可以将它放在一个try -- except子句中,但这似乎是一种相当乏味的方法。当然,有更好的选择来解决这个问题。
除了将其包装在try语句中之外,您还可以通过其他两种方法来抑制上下文管理器中的给定异常:
使用if返回True是否应抑制给定异常的条件。这是基于指定值抑制异常的文档。True
Python 2.x这将在不同版本中起作用Python 3.x。
使用contextlib.suppress给定的异常名称作为参数。
这只适用于版本> 3.3
第一个选项是一个值得注意的选项,因为它可以在大多数 Python 上运行,因此可移植性很重要。只需使用所需的异常初始化上下文管理器,然后__exit__添加一个if仅允许传播给定异常的子句即可完成此操作:
class contextMan:
def __init__(self, exception):
self.exception = exception
def __enter__(self):
print("Entering Context")
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting Context")
return isinstance(exc_value, self.exception)
if __name__ == "__main__":
with contextMan(IndexError):
raise IndexError
Run Code Online (Sandbox Code Playgroud)
现在,这将抑制 的任何实例IndexError或子类的任何实例,IndexError从而导致输出:
Entering Context
Exiting Context
Run Code Online (Sandbox Code Playgroud)
这种方法的缺点是,您要向每个实例添加一个额外的属性,并且本质上将两个不同的逻辑任务组合在一个对象中,而不是将它们分开。
第二种选择更加稳健、明确和通用。它是专门为此类场景创建的。它也是一个上下文管理器,因此通常可用于应抑制特定异常的任何情况。
它的调用签名的形式如下:
contextlib.suppress(*exceptions)
Run Code Online (Sandbox Code Playgroud)
哪里*exceptions有要抑制的异常元组。保持原始上下文管理器不变,我们现在可以创建一个嵌套上下文管理器,它也可以抑制特定的异常:
class contextMan:
def __enter__(self):
print("Entering Context")
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting Context")
if __name__ == "__main__":
with contextlib.suppress("IndexError")
with contextMan():
raise IndexError
Run Code Online (Sandbox Code Playgroud)
也可以将其写在同一行上,但这会导致语句相当冗长。这样做的明显缺点是每次使用上下文管理器时都会引入另一个语句。
尽管有两种选择,但应该有一种(最好只有一种)明显的方法来做到这一点,我相信第二种方法是明显的方法(至少对于最近的版本)。
| 归档时间: |
|
| 查看次数: |
6298 次 |
| 最近记录: |