Python uuu输入uuu/uuuu退出uuu与uuu初始化uuuu(或uuu新建uuuu)/uu删除__

Python uuu输入uuu/uuuu退出uuu与uuu初始化uuuu(或uuu新建uuuu)/uu删除__,python,constructor,destructor,with-statement,contextmanager,Python,Constructor,Destructor,With Statement,Contextmanager,我已经搜索过了,但我找不到任何好的理由来使用python的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu/\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu 据我所知,\uuuuuuuuuuuuuuuuuu进入/\uuuuuuuuuu退出用于作为上下文管理器的with语句,而with语句非常棒。但与此相对应的是,这些块中的任何代码都

我已经搜索过了,但我找不到任何好的理由来使用python的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
/
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

据我所知,
\uuuuuuuuuuuuuuuuuu进入
/
\uuuuuuuuuu退出
用于作为上下文管理器的
with
语句,而
with
语句非常棒。但与此相对应的是,这些块中的任何代码都只在该上下文中执行。通过使用这些而不是
\uuuuu init\uuuu
/
\uuuu del\uuuuu
,我似乎在与调用者创建一个隐式契约,调用者必须将
一起使用,但没有办法强制执行这样的契约,而契约只能通过文档(或阅读代码)进行通信。这似乎是个坏主意

使用
\uuuu init\uuuu
/
\uu del\uuuu
在带有
块的
内部,我似乎获得了相同的效果。但是通过使用它们而不是上下文管理方法,我的对象在其他场景中也很有用

那么,有人能提出一个令人信服的理由来解释为什么我会使用上下文管理方法而不是构造函数/析构函数方法吗

如果有更好的地方问这样的问题,请让我知道,但似乎没有太多关于这方面的好信息

跟进:
这个问题是基于一个不好的(但可能是常见的)假设,因为我总是使用
with
来实例化一个新对象,在这种情况下
\uuuuuuuuu init\uuuuu/\uuuu del\uuuuuu
\uuuuuu enter\uuuu/\uuuuuuuuuu exit\uuuuuu>的行为非常接近(除了您无法控制何时或是否执行
\uu del\uuu
之外,这取决于垃圾收集,如果先终止进程,则可能永远不会调用该进程)。但是如果您将
中预先存在的对象与
语句一起使用,它们当然是完全不同的。

您似乎忽略了几个差异:

  • 上下文管理器有机会仅为正在执行的块提供一个新对象。某些上下文管理器只返回
    self
    (与文件对象一样),但例如,数据库连接对象可能返回绑定到当前事务的游标对象

  • 上下文管理器不仅会收到上下文结束的通知,还会收到异常导致退出的通知。然后,上下文管理器可以决定处理该事件,或者在退出过程中做出不同的反应。再次以数据库连接为例,基于存在异常,您可以提交或中止事务

  • \uuuu del\uuuu
    仅在删除对对象的所有引用时调用。这意味着,如果您需要对对象进行多个引用,而这些引用可能是您控制的,也可能不是您控制的生命周期,则无法依赖于调用该对象。但是,上下文管理器出口是精确定义的

  • 上下文管理器可以重用,并且可以保持状态。重新创建数据库连接;您创建一次,然后将其作为上下文管理器反复使用,它将保持该连接打开。无需为此每次创建新对象

    例如,这对于线程锁很重要;您必须保持状态,以便一次只能有一个线程持有锁。为此,您可以创建一个锁对象,然后将
    与lock:
    一起使用,这样执行该节的不同线程可以在进入该上下文之前等待

\uuuuuuuuuuuuuuuuu进入
\uuuuuuuuuuu退出
方法构成了上下文管理器协议,只有在您真正想要管理上下文时才应该使用这些方法。上下文管理器的目标是简化常见的
尝试…最后
尝试…除了
模式,而不是管理单个实例的生存期。请参阅:

这个PEP在Python语言中添加了一个新的语句“with”,以便能够排除try/finally语句的标准用法


del x
不直接调用
x.\uuu del\uuuu()

您无法控制何时调用
。\uuuu del\uuu
,或者实际上调用

因此,使用
\uuuuu init\uuuu
/
\uuuu del\uuuu
进行上下文管理是不可靠的

通过使用这些,而不是
\uuuu init\uuuu
/
\uuu del\uuuu
,我似乎在与调用方创建一个隐式契约,它们必须与
一起使用
,但没有办法强制执行这样的契约

无论哪种方式,您都有一个约定。如果用户使用您的对象时没有意识到它在使用后需要清理,那么无论您如何实施清理,他们都会把事情搞砸。他们可能会永远保留对您对象的引用,例如,阻止
\uu del\uu
运行

如果您有需要特殊清理的对象,则需要明确此要求。您需要为用户
提供
功能和显式
关闭
或类似方法,以让用户控制何时进行清理。您不能将清理要求隐藏在
删除
方法中。您可能希望作为一项安全措施,也要实施
\uuuuuuu del\uuuu
,但不能使用
\uuuuuu del\uuuu
代替
,使用
或显式
关闭



话虽如此,Python并没有承诺
\uuuu del\uuu
将永远运行。当对象的refcount降至0时,标准实现将运行
\uuuu del\uuu
,但如果引用保留到脚本末尾,或者对象处于引用周期中,则可能不会发生这种情况。maki说,其他实现不使用refcountingng
\uu del\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu