我怎么知道何时可以/应该使用`with`关键字?

时间:2016-10-04 11:33:41

标签: python python-3.x with-statement

在C#中,当一个对象实现IDisposable时,应该使用using来保证在抛出异常时清理资源。例如,而不是:

var connection = new SqlConnection(...);
...
connection.Close();

需要写一下:

using (var connection = new SqlConnection(...))
{
    ...
}

因此,仅仅通过查看类的签名,我就确切地知道是否应该在using内初始化对象。

在Python 3中,类似的构造是with。与C#类似,它确保在退出with上下文时自动清理资源,即使出现错误也是如此。

但是,我不确定应该如何确定是否应该对特定类使用with。例如,an example from psycopg不使用with,这可能意味着:

  • 我不应该,或者:
  • 该示例是为Python 2编写的,或者:
  • 文档的作者不知道with语法,或者:
  • 作者决定不为了简单起见处理特殊情况。

一般情况下,我应该如何确定在初始化特定类的实例时是否应该使用with(假设文档中没有说明主题,并且我可以访问源代码)?

3 个答案:

答案 0 :(得分:2)

with用于上下文管理器。 在代码级别,上下文管理器必须定义两个方法:

  • __enter__(self)
  • __exit__(self, type, value, traceback)

请注意,有些类装饰器可以将其他简单的类/函数转换为上下文管理器 - 有关示例,请参阅contextlib

答案 1 :(得分:2)

关于何时使用它:

没有人强迫你使用with声明,它只是语法糖,可以让你的生活更轻松。如果您使用或不使用完全取决于您,但通常建议您这样做。 (我们很健忘,with ...看起来比显式初始化资源/最终化追索权更好。

可以使用它时:

可以使用它时,可以归结为检查它是否定义了上下文管理器协议。这可能就像尝试使用with并看到它失败一样简单: - )

如果你动态地需要检查一个对象一个上下文管理器,你有两个选择。

首先,等待Python 3.6的稳定版本,该版本为上下文管理器ABC定义ContextManager,可以在issubclass/isinstance项检查中使用:

>>> from typing import ContextManager
>>> class foo:
...     def __enter__(self): pass
...     def __exit__(self): pass
... 
>>> isinstance(foo(), ContextManager)
True
>>> class foo2: pass
... 
>>> isinstance(foo2(), ContextManager)
False

或者,创建自己的小功能来检查它:

def iscontext(inst):
    cls = type(inst)
    return (any("__enter__" in vars(a) for a in cls.__mro__) and
            any("__exit__" in vars(a) for a in cls.__mro__))

最后一点,with语句出现在Python 23中,您看到的用例可能只是不知道它: - )。

答案 2 :(得分:0)

只要您需要在执行语句之前和之后执行某些类似的操作,就应该使用with。例如:

  • 想要执行SQL查询吗?您需要安全地打开和关闭连接。使用with
  • 想要对文件执行某些操作吗?您必须安全地打开和关闭文件。使用with
  • 想要将一些数据存储在临时文件中以执行某些任务吗?您需要创建目录,并在完成后进行清理。使用with,依此类推。 。 。

在查询执行之前要执行的所有操作,将其添加到__enter__()方法。以及之后要执行的操作,将其添加到__exit__()方法。

关于with的一个好处是,即使__exit__中的代码引发任何with Exception >