我怎么知道我什么时候 can/should 使用了 `with` 关键字?
How do I know when I can/should use `with` keyword?
在C#中,当一个对象实现IDisposable
时,应该使用using
来保证在抛出异常时资源会被清理。例如,而不是:
var connection = new SqlConnection(...);
...
connection.Close();
一个需要写:
using (var connection = new SqlConnection(...))
{
...
}
因此,仅通过查看 class 的签名,我就确切地知道我是否应该在 using
.
中初始化对象
在Python 3中,一个类似的结构是with
。与 C# 类似,它确保在退出 with
上下文时自动清理资源,即使出现错误也是如此。
但是,我不确定我应该如何确定 with
是否应该用于特定的 class。例如,an example from psycopg
不使用 with
,这可能意味着:
- 我也不应该,或者:
- 例子是为Python2写的,或者:
- 文档的作者不知道
with
语法,或者:
- 为了简单起见,作者决定不处理异常情况。
一般来说,在初始化特定class的实例时,我应该如何确定是否应该使用with
(假设文档没有说明这个问题,并且我可以访问源代码代码)?
with
用于上下文管理器。
在代码级别,上下文管理器必须定义两个方法:
__enter__(self)
__exit__(self, type, value, traceback)
.
请注意,有 class 装饰器可以将原本简单的 classes/functions 转换为上下文管理器 - 请参阅 contextlib 了解一些示例
关于您何时应该使用它:
没有人强迫您使用 with
语句,它只是让您的生活更轻松的语法糖。是否使用它完全取决于您,但通常建议您这样做。 (我们很健忘,with ...
看起来比显式初始化 resource/finalize 追索调用更好)。
当您可以使用它时:
当您可以使用它时,归结为检查它是否定义了上下文管理器协议。这可能就像尝试使用 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
中,您看到的用例可能只是没有意识到它 :-)。
只要您需要在执行语句前后执行一些类似的操作,就应该使用 with
。例如:
- 要执行SQL查询?您需要打开和关闭连接safely.Use
with
.
- 要对文件执行一些操作吗? 您必须安全地打开和关闭文件。使用
with
- 想要在临时文件中存储一些数据以执行某些任务?您需要创建目录,并在完成后清理它。使用
with
,依此类推。 . .
你想在查询执行之前执行的一切,将它添加到 __enter__()
方法。以及之后要执行的操作,将其添加到 __exit__()
方法中。
with
的一个好处是,即使 with
中的代码引发任何 Exception
[=34,__exit__
也会执行=]
在C#中,当一个对象实现IDisposable
时,应该使用using
来保证在抛出异常时资源会被清理。例如,而不是:
var connection = new SqlConnection(...);
...
connection.Close();
一个需要写:
using (var connection = new SqlConnection(...))
{
...
}
因此,仅通过查看 class 的签名,我就确切地知道我是否应该在 using
.
在Python 3中,一个类似的结构是with
。与 C# 类似,它确保在退出 with
上下文时自动清理资源,即使出现错误也是如此。
但是,我不确定我应该如何确定 with
是否应该用于特定的 class。例如,an example from psycopg
不使用 with
,这可能意味着:
- 我也不应该,或者:
- 例子是为Python2写的,或者:
- 文档的作者不知道
with
语法,或者: - 为了简单起见,作者决定不处理异常情况。
一般来说,在初始化特定class的实例时,我应该如何确定是否应该使用with
(假设文档没有说明这个问题,并且我可以访问源代码代码)?
with
用于上下文管理器。
在代码级别,上下文管理器必须定义两个方法:
__enter__(self)
__exit__(self, type, value, traceback)
.
请注意,有 class 装饰器可以将原本简单的 classes/functions 转换为上下文管理器 - 请参阅 contextlib 了解一些示例
关于您何时应该使用它:
没有人强迫您使用 with
语句,它只是让您的生活更轻松的语法糖。是否使用它完全取决于您,但通常建议您这样做。 (我们很健忘,with ...
看起来比显式初始化 resource/finalize 追索调用更好)。
当您可以使用它时:
当您可以使用它时,归结为检查它是否定义了上下文管理器协议。这可能就像尝试使用 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
中,您看到的用例可能只是没有意识到它 :-)。
只要您需要在执行语句前后执行一些类似的操作,就应该使用 with
。例如:
- 要执行SQL查询?您需要打开和关闭连接safely.Use
with
. - 要对文件执行一些操作吗? 您必须安全地打开和关闭文件。使用
with
- 想要在临时文件中存储一些数据以执行某些任务?您需要创建目录,并在完成后清理它。使用
with
,依此类推。 . .
你想在查询执行之前执行的一切,将它添加到 __enter__()
方法。以及之后要执行的操作,将其添加到 __exit__()
方法中。
with
的一个好处是,即使 with
中的代码引发任何 Exception
[=34,__exit__
也会执行=]