在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
,这可能意味着:
with
语法,或者:一般情况下,我应该如何确定在初始化特定类的实例时是否应该使用with
(假设文档中没有说明主题,并且我可以访问源代码)?
答案 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 2
和3
中,您看到的用例可能只是不知道它: - )。
答案 2 :(得分:0)
只要您需要在执行语句之前和之后执行某些类似的操作,就应该使用with
。例如:
with
。with
with
,依此类推。 。 。 在查询执行之前要执行的所有操作,将其添加到__enter__()
方法。以及之后要执行的操作,将其添加到__exit__()
方法。
关于with
的一个好处是,即使__exit__
中的代码引发任何with
Exception
>