我已经搜索过,但找不到任何使用 python 的充分理由__enter__
/__exit__
而不是__init__
(or __new__
?) / __del__
.
我明白那个__enter__
/ __exit__
旨在与使用with
作为上下文管理器的声明,以及with
声明很棒。但与之相对应的是,这些块中的任何代码都是only在该上下文中执行。通过使用这些而不是__init__
/ __del__
我似乎正在与调用者创建一个他们必须使用的隐式合约with
,但是没有办法执行这样的合同,并且合同只能通过文档(或阅读代码)来传达。这似乎是个坏主意。
我似乎使用得到了相同的效果__init__
/ __del__
里面的一个with
堵塞。但是通过使用它们而不是上下文管理方法,我的对象在其他场景中也很有用。
那么有人能想出一个令人信服的理由来解释为什么我会这么做吗?ever想要使用上下文管理方法而不是构造函数/析构函数方法?
如果有更好的地方可以问这样的问题,请告诉我,但似乎没有太多关于此的好信息。
跟进:
这个问题是基于一个糟糕的(但可能是常见的)假设,因为我总是使用with
实例化一个新对象,在这种情况下__init__/__del__
非常接近相同的行为__enter__/__exit__
(除了你无法控制何时或是否__del__
将被执行,这取决于垃圾收集,如果进程首先终止,则可能永远不会被调用)。但是如果你使用预先存在的对象with
他们的说法当然是截然不同的。
您似乎忽略了几个差异:
上下文管理器有机会为您正在执行的块提供一个新对象。一些上下文管理器只是返回self
那里(就像文件对象一样),但是,作为一个例子,数据库连接对象可以返回与当前事务绑定的游标对象。
上下文管理器不仅会收到上下文结束的通知,还会收到退出是否由异常引起的通知。然后它可以决定处理该事件或在退出期间做出不同的反应。再次以数据库连接为例,根据是否存在异常,您可以提交或中止事务。
__del__
仅在以下情况下调用all对对象的引用被删除。这意味着如果您需要对它进行多个引用(您可能会或可能不会控制其生命周期),则不能依赖它被调用。然而,上下文管理器出口是精确定义的。
-
上下文管理器可以是reused,并且他们可以保持状态。再次连接数据库;您创建它一次,然后一次又一次地将它用作上下文管理器,并且它将保持该连接打开。不需要每次都创建一个新对象。
例如,这对于线程锁很重要;你have保持状态,以便一次只有一个线程可以持有锁。您可以通过创建来做到这一点one锁定对象,然后使用with lock:
因此,执行该部分的不同线程可以在进入该上下文之前等待。
The __enter__
and __exit__
方法形成上下文管理器协议,并且只有当您确实想要管理上下文时才应该使用它们。上下文管理器的目标是简化常见的try...finally
and try...except
模式,而不是管理单个实例的生命周期。看PEP 343 –“with”声明 https://www.python.org/dev/peps/pep-0343/:
此 PEP 在 Python 语言中添加了一个新语句“with”,以便能够分解 try/finally 语句的标准用法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)