如何在上下文管理器中抑制给定的异常?

2021-05-16 08:26:49 发布

您现在位置:Python中文网/ 问答频道 /正文

在试图忽略上下文管理器执行期间引发的异常时,我有什么选择?同样,下面的简单上下文管理器只传播结果,导致它结束执行,除非捕获到:

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

我当然可以用try -- except子句来描述它,但这似乎是一种相当乏味的方法。当然,解决这个问题还有更好的选择。在

1条回答
网友
1楼 ·

除了在try语句中包装它之外,还有两种方法可以在上下文管理器中禁止给定的异常:

  1. 使用一个if条件,如果给定的异常应被抑制,则返回True。这是基于documentation,它指定True值抑制异常。在

    这将在Python 2.xPython 3.x版本上起作用。

  2. 使用具有给定异常名称的^{}作为参数。在

    这只适用于版本> 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

这将禁止IndexError的任何实例或{}子类的任何实例,从而产生以下输出:

^{pr2}$

这种方法的缺点是向每个实例添加一个额外的属性,实际上是在一个对象中组合两个不同的逻辑任务,而不是将它们分离。在


第二个选项是更健壮的显式通用。它是专门为这类场景而创建的。它也是一个上下文管理器,因此,通常可以用于任何需要抑制特定异常的情况。在

它的调用签名形式如下:

 contextlib.suppress(*exceptions) 

其中*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

也可以写在同一行,但这会导致一个相当长的声明。这样做的明显缺点是每次使用上下文管理器时都会引入另一个语句。在

即使有两种选择,也应该有一种最好只有一种明显的方法来实现这一点,我相信第二种方法是显而易见的(至少对于最近的版本)。在

相关问题