uTools-Manuals/docs/python/weakref.html
2019-04-21 11:50:48 +08:00

136 lines
56 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="body" role="main"><div class="section" id="module-weakref"><h1><span class="yiyi-st" id="yiyi-10">8.8. <a class="reference internal" href="#module-weakref" title="weakref: Support for weak references and weak dictionaries."><code class="xref py py-mod docutils literal"><span class="pre">weakref</span></code></a> - 弱参考</span></h1><p><span class="yiyi-st" id="yiyi-11"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/weakref.py">Lib / weakref.py</a></span></p><p><span class="yiyi-st" id="yiyi-12"><a class="reference internal" href="#module-weakref" title="weakref: Support for weak references and weak dictionaries."><code class="xref py py-mod docutils literal"><span class="pre">weakref</span></code></a>模块允许Python程序员为对象创建<em class="dfn">弱引用</em></span></p><p><span class="yiyi-st" id="yiyi-13">在下文中,术语<em class="dfn">指代</em>意味着弱引用所引用的对象。</span></p><p><span class="yiyi-st" id="yiyi-14">对对象的弱引用不足以保持对象存活:当对引用对象的仅剩余引用是弱引用时,<a class="reference internal" href="../glossary.html#term-garbage-collection"><span class="xref std std-term">garbage collection</span></a>可以自由地销毁指针,并将其内存重用于其他内容。</span><span class="yiyi-st" id="yiyi-15">然而,直到对象被实际销毁,弱引用可以返回对象,即使没有对它的强引用。</span></p><p><span class="yiyi-st" id="yiyi-16">弱引用的主要用途是实现持有大对象的高速缓存或映射,其中希望大对象不会因为它出现在高速缓存或映射中而保持活着。</span></p><p><span class="yiyi-st" id="yiyi-17">例如,如果您有一些大的二进制图像对象,您可能希望将一个名称与每个对象相关联。</span><span class="yiyi-st" id="yiyi-18">如果您使用Python字典将名称映射到图像或将图像映射到名称则图像对象将仍然存在因为它们在字典中显示为值或键。</span><span class="yiyi-st" id="yiyi-19"><a class="reference internal" href="#module-weakref" title="weakref: Support for weak references and weak dictionaries."><code class="xref py py-mod docutils literal"><span class="pre">weakref</span></code></a>模块提供的<a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a><a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>类是一种替代方法,使用弱引用来构造不保留对象的映射,它们出现在映射对象中。</span><span class="yiyi-st" id="yiyi-20">例如,如果图像对象是<a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>中的值,则当对该图像对象的最后剩余引用是弱映射所持有的弱引用时,垃圾容器可以回收该对象,并且其弱映射中的相应条目被简单地删除。</span></p><p><span class="yiyi-st" id="yiyi-21"><a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a><a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>在其实现中使用弱引用,在垃圾容器回收键或值时通知弱字典的弱引用上设置回调函数。</span><span class="yiyi-st" id="yiyi-22"><a class="reference internal" href="#weakref.WeakSet" title="weakref.WeakSet"><code class="xref py py-class docutils literal"><span class="pre">WeakSet</span></code></a>实现<a class="reference internal" href="stdtypes.html#set" title="set"><code class="xref py py-class docutils literal"><span class="pre">set</span></code></a>接口,但保持对其元素的弱引用,就像<a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-23"><a class="reference internal" href="#weakref.finalize" title="weakref.finalize"><code class="xref py py-class docutils literal"><span class="pre">finalize</span></code></a>提供了一种直接的方式来注册要在对象被垃圾回收时调用的清除函数。</span><span class="yiyi-st" id="yiyi-24">这比在原始弱引用上设置回调函数更容易使用,因为模块自动确保终结器保持活动直到对象被收集。</span></p><p><span class="yiyi-st" id="yiyi-25">大多数程序应该发现使用这些弱容器类型之一或<a class="reference internal" href="#weakref.finalize" title="weakref.finalize"><code class="xref py py-class docutils literal"><span class="pre">finalize</span></code></a>是他们需要的 - 通常不需要直接创建自己的弱引用。</span><span class="yiyi-st" id="yiyi-26">低级机械由<a class="reference internal" href="#module-weakref" title="weakref: Support for weak references and weak dictionaries."><code class="xref py py-mod docutils literal"><span class="pre">weakref</span></code></a>模块暴露,以实现高级用途。</span></p><p><span class="yiyi-st" id="yiyi-27">不是所有的对象都可以弱引用这些对象可以包括类实例用Python但不是C写的函数实例方法frozensets一些<a class="reference internal" href="../glossary.html#term-file-object"><span class="xref std std-term">file objects</span></a><a class="reference internal" href="../glossary.html#term-generator"><span class="xref std std-term">generator</span></a> 套接字数组deques正则表达式模式对象和代码对象。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-28"><span class="versionmodified">在版本3.2中更改:</span>添加了对thread.lockthreading.Lock和代码对象的支持。</span></p></div><p><span class="yiyi-st" id="yiyi-29">一些内建类型,如<a class="reference internal" href="stdtypes.html#list" title="list"><code class="xref py py-class docutils literal"><span class="pre">list</span></code></a><a class="reference internal" href="stdtypes.html#dict" title="dict"><code class="xref py py-class docutils literal"><span class="pre">dict</span></code></a>不直接支持弱引用,但可以通过子类化添加支持:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">Dict</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">pass</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">Dict</span><span class="p">(</span><span class="n">red</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">green</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">blue</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># this object is weak referenceable</span>
</code></pre><p><span class="yiyi-st" id="yiyi-30">其他内建类型如<a class="reference internal" href="stdtypes.html#tuple" title="tuple"><code class="xref py py-class docutils literal"><span class="pre">tuple</span></code></a><a class="reference internal" href="functions.html#int" title="int"><code class="xref py py-class docutils literal"><span class="pre">int</span></code></a>即使在子类化时也不支持弱引用这是一个实现细节可能在不同的Python实现中是不同的。</span><span class="yiyi-st" id="yiyi-31">)。</span></p><p><span class="yiyi-st" id="yiyi-32">扩展类型可以很容易地支持弱引用;请参阅<a class="reference internal" href="../extending/newtypes.html#weakref-support"><span>Weak Reference Support</span></a></span></p><dl class="class"><dt id="weakref.ref"><span class="yiyi-st" id="yiyi-33"><em class="property">class </em><code class="descclassname">weakref.</code><code class="descname">ref</code><span class="sig-paren">(</span><em>object</em><span class="optional">[</span>, <em>callback</em><span class="optional">]</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-34">返回对<em>对象</em>的弱引用。</span><span class="yiyi-st" id="yiyi-35">如果引用对象仍然存在,则可以通过调用引用对象来检索原始对象;如果引用对象不再活动,则调用引用对象将导致返回<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a></span><span class="yiyi-st" id="yiyi-36">如果提供<em>callback</em>而不是<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a>并且返回的weakref对象仍然有效则当对象即将完成时将调用回调弱引用对象将作为唯一的参数传递给回调函数指示物将不再可用。</span></p><p><span class="yiyi-st" id="yiyi-37">可以为同一对象构造许多弱引用。</span><span class="yiyi-st" id="yiyi-38">为每个弱引用注册的回调将从最近注册的回调调用到最早注册的回调。</span></p><p><span class="yiyi-st" id="yiyi-39">回调引发的异常将在标准错误输出上注明,但不能传播;它们的处理方式与从对象的<a class="reference internal" href="../reference/datamodel.html#object.__del__" title="object.__del__"><code class="xref py py-meth docutils literal"><span class="pre">__del__()</span></code></a>方法引发的异常完全相同。</span></p><p><span class="yiyi-st" id="yiyi-40">如果<em>对象</em>是可散列的,则弱引用<a class="reference internal" href="../glossary.html#term-hashable"><span class="xref std std-term">hashable</span></a></span><span class="yiyi-st" id="yiyi-41">即使在删除<em>对象</em>之后,它们仍将保持其散列值。</span><span class="yiyi-st" id="yiyi-42">如果<a class="reference internal" href="functions.html#hash" title="hash"><code class="xref py py-func docutils literal"><span class="pre">hash()</span></code></a>仅在<em>对象</em>删除后第一次调用,则调用将引发<a class="reference internal" href="exceptions.html#TypeError" title="TypeError"><code class="xref py py-exc docutils literal"><span class="pre">TypeError</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-43">弱引用支持相等测试,但不支持排序。</span><span class="yiyi-st" id="yiyi-44">如果引用仍然存在,则两个引用与它们的引用具有相同的等式关系(不管<em>回调</em>)。</span><span class="yiyi-st" id="yiyi-45">如果引用对象已被删除,则引用仅在引用对象是同一对象时相等。</span></p><p><span class="yiyi-st" id="yiyi-46">这是一个可子类型而不是工厂函数。</span></p><dl class="attribute"><dt id="weakref.ref.__callback__"><span class="yiyi-st" id="yiyi-47"><code class="descname">__ callback __</code> </span></dt><dd><p><span class="yiyi-st" id="yiyi-48">此只读属性返回当前与weakref关联的回调。</span><span class="yiyi-st" id="yiyi-49">如果没有回调或者如果weakref的引用不再活那么该属性将具有值<code class="docutils literal"><span class="pre">None</span></code></span></p></dd></dl><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-50"><span class="versionmodified">在版本3.4中已更改:</span>添加了<a class="reference internal" href="#weakref.ref.__callback__" title="weakref.ref.__callback__"><code class="xref py py-attr docutils literal"><span class="pre">__callback__</span></code></a>属性。</span></p></div></dd></dl><dl class="function"><dt id="weakref.proxy"><span class="yiyi-st" id="yiyi-51"><code class="descclassname">weakref.</code><code class="descname">proxy</code><span class="sig-paren">(</span><em>object</em><span class="optional">[</span>, <em>callback</em><span class="optional">]</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-52">将代理返回到使用弱引用的<em>对象</em></span><span class="yiyi-st" id="yiyi-53">这支持在大多数上下文中使用代理,而不需要使用弱引用对象的显式取消引用。</span><span class="yiyi-st" id="yiyi-54">根据<em>对象</em>是否可调用,返回的对象将具有<code class="docutils literal"><span class="pre">ProxyType</span></code><code class="docutils literal"><span class="pre">CallableProxyType</span></code>的类型。</span><span class="yiyi-st" id="yiyi-55">代理对象不是<a class="reference internal" href="../glossary.html#term-hashable"><span class="xref std std-term">hashable</span></a>,无论指定对象;这避免了与它们的基本上可变性质相关的许多问题,并且防止它们用作字典键。</span><span class="yiyi-st" id="yiyi-56"><em>回调</em><a class="reference internal" href="#weakref.ref" title="weakref.ref"><code class="xref py py-func docutils literal"><span class="pre">ref()</span></code></a>函数同名的参数相同。</span></p></dd></dl><dl class="function"><dt id="weakref.getweakrefcount"><span class="yiyi-st" id="yiyi-57"><code class="descclassname">weakref.</code><code class="descname">getweakrefcount</code><span class="sig-paren">(</span><em>object</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-58">返回引用<em>对象</em>的弱引用和代理的数量。</span></p></dd></dl><dl class="function"><dt id="weakref.getweakrefs"><span class="yiyi-st" id="yiyi-59"><code class="descclassname">weakref.</code><code class="descname">getweakrefs</code><span class="sig-paren">(</span><em>object</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-60">返回引用<em>对象</em>的所有弱引用和代理对象的列表。</span></p></dd></dl><dl class="class"><dt id="weakref.WeakKeyDictionary"><span class="yiyi-st" id="yiyi-61"> <em class="property">class </em><code class="descclassname">weakref.</code><code class="descname">WeakKeyDictionary</code><span class="sig-paren">(</span><span class="optional">[</span><em>dict</em><span class="optional">]</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-62">弱引用键的映射类。</span><span class="yiyi-st" id="yiyi-63">当不再有对键的强引用时,字典中的条目将被丢弃。</span><span class="yiyi-st" id="yiyi-64">这可以用于将附加数据与应用程序的其他部分拥有的对象关联,而不向这些对象添加属性。</span><span class="yiyi-st" id="yiyi-65">这对于覆盖属性访问的对象尤其有用。</span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-66">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-67">注意:因为<a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a>是建立在Python字典之上因此在迭代它时不能改变大小。</span><span class="yiyi-st" id="yiyi-68">这可能难以确保<a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a>,因为在迭代期间由程序执行的动作可能导致词典中的项目被“魔术”消失(作为垃圾容器的副作用)。</span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-69"><a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a>对象还有以下附加方法。</span><span class="yiyi-st" id="yiyi-70">这些直接暴露内部引用。</span><span class="yiyi-st" id="yiyi-71">引用不能保证在使用时是“活的”,因此调用引用的结果需要在使用之前进行检查。</span><span class="yiyi-st" id="yiyi-72">这可以用于避免创建引用,这将导致垃圾收集器将密钥保持比所需更长的时间。</span></p><dl class="method"><dt id="weakref.WeakKeyDictionary.keyrefs"><span class="yiyi-st" id="yiyi-73"><code class="descclassname">WeakKeyDictionary.</code><code class="descname">keyrefs</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-74">返回键的弱引用的可迭代。</span></p></dd></dl><dl class="class"><dt id="weakref.WeakValueDictionary"><span class="yiyi-st" id="yiyi-75"> <em class="property">class </em><code class="descclassname">weakref.</code><code class="descname">WeakValueDictionary</code><span class="sig-paren">(</span><span class="optional">[</span><em>dict</em><span class="optional">]</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-76">弱引用值的映射类。</span><span class="yiyi-st" id="yiyi-77">当没有对值的强引用存在时,字典中的条目将被丢弃。</span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-78">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-79">注意:因为<a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>是建立在Python字典之上所以在迭代它时不能改变大小。</span><span class="yiyi-st" id="yiyi-80">这可能难以确保<a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>,因为在迭代期间由程序执行的动作可能导致词典中的项目被“魔术”消失(作为垃圾容器的副作用)。</span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-81"><a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>对象还有以下附加方法。</span><span class="yiyi-st" id="yiyi-82">这些方法具有与<a class="reference internal" href="#weakref.WeakKeyDictionary" title="weakref.WeakKeyDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakKeyDictionary</span></code></a>对象的<code class="xref py py-meth docutils literal"><span class="pre">keyrefs()</span></code>方法相同的问题。</span></p><dl class="method"><dt id="weakref.WeakValueDictionary.valuerefs"><span class="yiyi-st" id="yiyi-83"><code class="descclassname">WeakValueDictionary.</code><code class="descname">valuerefs</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-84">返回值的弱引用的可迭代。</span></p></dd></dl><dl class="class"><dt id="weakref.WeakSet"><span class="yiyi-st" id="yiyi-85"> <em class="property">class </em><code class="descclassname">weakref.</code><code class="descname">WeakSet</code><span class="sig-paren">(</span><span class="optional">[</span><em>elements</em><span class="optional">]</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-86">设置保持对其元素的弱引用的类。</span><span class="yiyi-st" id="yiyi-87">当没有对它的强引用存在时,元素将被丢弃。</span></p></dd></dl><dl class="class"><dt id="weakref.WeakMethod"><span class="yiyi-st" id="yiyi-88"> <em class="property">class </em><code class="descclassname">weakref.</code><code class="descname">WeakMethod</code><span class="sig-paren">(</span><em>method</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-89">自定义<a class="reference internal" href="#weakref.ref" title="weakref.ref"><code class="xref py py-class docutils literal"><span class="pre">ref</span></code></a>子类,它模拟绑定方法的弱引用(即,在类上定义并在实例上查找的方法)。</span><span class="yiyi-st" id="yiyi-90">由于绑定方法是短暂的,一个标准的弱引用不能保持它。</span><span class="yiyi-st" id="yiyi-91"><a class="reference internal" href="#weakref.WeakMethod" title="weakref.WeakMethod"><code class="xref py py-class docutils literal"><span class="pre">WeakMethod</span></code></a>具有特殊代码,用于重新创建绑定方法,直到对象或原始函数死亡:</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">"method called!"</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">c</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">ref</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">method</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">WeakMethod</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">method</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="p">()</span>
<span class="go">&lt;bound method C.method of &lt;__main__.C object at 0x7fc859830220&gt;&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="p">()()</span>
<span class="go">method called!</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">c</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">gc</span><span class="o">.</span><span class="n">collect</span><span class="p">()</span>
<span class="go">0</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="p">()</span>
<span class="go">&gt;&gt;&gt;</span>
</code></pre><div class="versionadded"><p><span class="yiyi-st" id="yiyi-92"><span class="versionmodified">版本3.4中的新功能。</span></span></p></div></dd></dl><dl class="class"><dt id="weakref.finalize"><span class="yiyi-st" id="yiyi-93"><em class="property">class </em><code class="descclassname">weakref.</code><code class="descname">finalize</code><span class="sig-paren">(</span><em>obj</em>, <em>func</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-94">返回一个可调用的终结器对象,当<em>obj</em>被垃圾收集时将被调用。</span><span class="yiyi-st" id="yiyi-95">与普通弱引用不同,终结器将始终存活,直到收集引用对象,从而大大简化了生命周期管理。</span></p><p><span class="yiyi-st" id="yiyi-96">终结器被认为是<em>存活</em>,直到它被调用(显式地或在垃圾容器),然后是<em></em></span><span class="yiyi-st" id="yiyi-97">调用实时终结器将返回评估<code class="docutils literal"><span class="pre">func* arg</span> <span class="pre">** kwargs</span></code>的结果,而调用死终结器返回<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-98">垃圾容器期间由finalizer回调引发的异常将显示在标准错误输出上但不能传播。</span><span class="yiyi-st" id="yiyi-99">它们以与从对象的<a class="reference internal" href="../reference/datamodel.html#object.__del__" title="object.__del__"><code class="xref py py-meth docutils literal"><span class="pre">__del__()</span></code></a>方法或弱引用的回调引发的异常相同的方式处理。</span></p><p><span class="yiyi-st" id="yiyi-100">当程序退出时,除非其<a class="reference internal" href="atexit.html#module-atexit" title="atexit: Register and execute cleanup functions."><code class="xref py py-attr docutils literal"><span class="pre">atexit</span></code></a>属性已设置为false否则将调用每个剩余的实时终结器。</span><span class="yiyi-st" id="yiyi-101">他们被称为创造的相反顺序。</span></p><p><span class="yiyi-st" id="yiyi-102">当模块全局变量被<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a>替换时,终结器将不会在<a class="reference internal" href="../glossary.html#term-interpreter-shutdown"><span class="xref std std-term">interpreter shutdown</span></a>的后面部分调用其回调。</span></p><dl class="method"><dt id="weakref.finalize.__call__"><span class="yiyi-st" id="yiyi-103"><code class="descname">__call__</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-104">如果<em>self</em>是活着的,则将其标记为死,并返回调用<code class="docutils literal"><span class="pre">func* args</span> <span class="pre">** kwargs t1&gt;</span></code></span><span class="yiyi-st" id="yiyi-105">如果<em>self</em>已失效,则返回<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a></span></p></dd></dl><dl class="method"><dt id="weakref.finalize.detach"><span class="yiyi-st" id="yiyi-106"><code class="descname">detach</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-107">如果<em>self</em>是活着的,则将其标记为死,并返回元组<code class="docutils literal"><span class="pre">obj</span> <span class="pre">func</span> <span class="pre">args t4 &gt; <span class="pre">kwargs</span></span></code></span><span class="yiyi-st" id="yiyi-108">如果<em>self</em>已失效,则返回<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a></span></p></dd></dl><dl class="method"><dt id="weakref.finalize.peek"><span class="yiyi-st" id="yiyi-109"><code class="descname">peek</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-110">如果<em>self</em>存活,则返回元组<code class="docutils literal"><span class="pre">obj t&gt;&gt; <span class="pre">func</span> <span class="pre">args</span> <span class="pre">kwargs </span></span></code></span><span class="yiyi-st" id="yiyi-111">如果<em>self</em>已失效,则返回<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a></span></p></dd></dl><dl class="attribute"><dt id="weakref.finalize.alive"><span class="yiyi-st" id="yiyi-112"><code class="descname">alive</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-113">属性如果终结器是活的则为true否则为false。</span></p></dd></dl><dl class="attribute"><dt id="weakref.finalize.atexit"><span class="yiyi-st" id="yiyi-114"><code class="descname">atexit</code> </span></dt><dd><p><span class="yiyi-st" id="yiyi-115">一个可写的布尔属性默认情况下为true。</span><span class="yiyi-st" id="yiyi-116">当程序退出时,它调用<a class="reference internal" href="#weakref.finalize.atexit" title="weakref.finalize.atexit"><code class="xref py py-attr docutils literal"><span class="pre">atexit</span></code></a>为真的所有剩余的活终结器。</span><span class="yiyi-st" id="yiyi-117">他们被称为创造的相反顺序。</span></p></dd></dl><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-118">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-119">重要的是确保<em>func</em><em>args</em><em>kwargs</em>不拥有对<em>obj</em>的任何引用间接,因为否则<em>obj</em>永远不会被垃圾收集。</span><span class="yiyi-st" id="yiyi-120">特别地,<em>func</em>不应该是<em>obj</em>的绑定方法。</span></p></div><div class="versionadded"><p><span class="yiyi-st" id="yiyi-121"><span class="versionmodified">版本3.4中的新功能。</span></span></p></div></dd></dl><dl class="data"><dt id="weakref.ReferenceType"><span class="yiyi-st" id="yiyi-122"><code class="descclassname">weakref.</code><code class="descname">ReferenceType</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-123">弱引用对象的类型对象。</span></p></dd></dl><dl class="data"><dt id="weakref.ProxyType"><span class="yiyi-st" id="yiyi-124"><code class="descclassname">weakref.</code><code class="descname">ProxyType</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-125">不可调用对象的代理的类型对象。</span></p></dd></dl><dl class="data"><dt id="weakref.CallableProxyType"><span class="yiyi-st" id="yiyi-126"><code class="descclassname">weakref.</code><code class="descname">CallableProxyType</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-127">可调用对象的代理的类型对象。</span></p></dd></dl><dl class="data"><dt id="weakref.ProxyTypes"><span class="yiyi-st" id="yiyi-128"><code class="descclassname">weakref.</code><code class="descname">ProxyTypes</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-129">包含代理的所有类型对象的序列。</span><span class="yiyi-st" id="yiyi-130">这可以使测试对象是否是代理而不依赖于命名这两种代理类型更简单。</span></p></dd></dl><dl class="exception"><dt id="weakref.ReferenceError"><span class="yiyi-st" id="yiyi-131"><em class="property">exception </em><code class="descclassname">weakref.</code><code class="descname">ReferenceError</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-132">使用代理对象但已收集基础对象时引发的异常。</span><span class="yiyi-st" id="yiyi-133">这与标准<a class="reference internal" href="exceptions.html#ReferenceError" title="ReferenceError"><code class="xref py py-exc docutils literal"><span class="pre">ReferenceError</span></code></a>异常相同。</span></p></dd></dl><div class="admonition seealso"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-134">也可以看看</span></p><dl class="last docutils"><dt><span class="yiyi-st" id="yiyi-135"><span class="target" id="index-0"></span> <a class="pep reference external" href="https://www.python.org/dev/peps/pep-0205"><strong>PEP 205</strong></a> - 弱参考</span></dt><dd><span class="yiyi-st" id="yiyi-136">此功能的提议和基本原理,包括指向早期实现的链接以及其他语言中类似功能的信息。</span></dd></dl></div><div class="section" id="weak-reference-objects"><h2><span class="yiyi-st" id="yiyi-137">8.8.1.</span><span class="yiyi-st" id="yiyi-138">弱参考对象</span></h2><p><span class="yiyi-st" id="yiyi-139">弱引用对象除了<a class="reference internal" href="#weakref.ref.__callback__" title="weakref.ref.__callback__"><code class="xref py py-attr docutils literal"><span class="pre">ref.__callback__</span></code></a>之外没有方法和属性。</span><span class="yiyi-st" id="yiyi-140">弱引用对象允许通过调用引用对象来获得引用对象,如果它仍然存在:</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">weakref</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Object</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">pass</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">o</span> <span class="o">=</span> <span class="n">Object</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">ref</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">o2</span> <span class="o">=</span> <span class="n">r</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">o</span> <span class="ow">is</span> <span class="n">o2</span>
<span class="go">True</span>
</code></pre><p><span class="yiyi-st" id="yiyi-141">如果引用对象不再存在,则调用引用对象返回<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a></span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">o</span><span class="p">,</span> <span class="n">o2</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="p">())</span>
<span class="go">None</span>
</code></pre><p><span class="yiyi-st" id="yiyi-142">测试弱引用对象是否仍然活动应使用表达式<code class="docutils literal"><span class="pre">ref()</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span></code></span><span class="yiyi-st" id="yiyi-143">通常,需要使用引用对象的应用程序代码应遵循此模式:</span></p><pre><code class="language-python"><span></span><span class="c1"># r is a weak reference object</span>
<span class="n">o</span> <span class="o">=</span> <span class="n">r</span><span class="p">()</span>
<span class="k">if</span> <span class="n">o</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># referent has been garbage collected</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Object has been deallocated; can't frobnicate."</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Object is still live!"</span><span class="p">)</span>
<span class="n">o</span><span class="o">.</span><span class="n">do_something_useful</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-144">使用“活性”的单独测试在线程应用程序中创建竞争条件;另一个线程可能导致弱引用在调用弱引用之前变得无效;上面显示的习语在线程应用程序以及单线程应用程序中是安全的。</span></p><p><span class="yiyi-st" id="yiyi-145">可以通过子类化创建<a class="reference internal" href="#weakref.ref" title="weakref.ref"><code class="xref py py-class docutils literal"><span class="pre">ref</span></code></a>对象的专用版本。</span><span class="yiyi-st" id="yiyi-146">这用于实现<a class="reference internal" href="#weakref.WeakValueDictionary" title="weakref.WeakValueDictionary"><code class="xref py py-class docutils literal"><span class="pre">WeakValueDictionary</span></code></a>以减少映射中每个条目的内存开销。</span><span class="yiyi-st" id="yiyi-147">这对于将附加信息与引用相关联可能是最有用的,但是也可以用于在调用所述对象的调用上插入附加处理。</span></p><p><span class="yiyi-st" id="yiyi-148">此示例显示如何使用<a class="reference internal" href="#weakref.ref" title="weakref.ref"><code class="xref py py-class docutils literal"><span class="pre">ref</span></code></a>的子类来存储有关对象的附加信息,并影响在访问引用对象时返回的值:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">weakref</span>
<span class="k">class</span> <span class="nc">ExtendedRef</span><span class="p">(</span><span class="n">weakref</span><span class="o">.</span><span class="n">ref</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">annotations</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">ExtendedRef</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">ob</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__counter</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">annotations</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Return a pair containing the referent and the number of</span>
<span class="sd"> times the reference has been called.</span>
<span class="sd"> """</span>
<span class="n">ob</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">ExtendedRef</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__call__</span><span class="p">()</span>
<span class="k">if</span> <span class="n">ob</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__counter</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">ob</span> <span class="o">=</span> <span class="p">(</span><span class="n">ob</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__counter</span><span class="p">)</span>
<span class="k">return</span> <span class="n">ob</span>
</code></pre></div><div class="section" id="example"><h2><span class="yiyi-st" id="yiyi-149">8.8.2.</span><span class="yiyi-st" id="yiyi-150">示例</span></h2><p><span class="yiyi-st" id="yiyi-151">这个简单的例子显示了应用程序如何使用对象ID来检索它之前已经看到的对象。</span><span class="yiyi-st" id="yiyi-152">然后可以在其他数据结构中使用对象的ID而不强制对象保持活动但是如果对象仍然可以通过ID检索。</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">weakref</span>
<span class="n">_id2obj_dict</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">WeakValueDictionary</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">remember</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="n">oid</span> <span class="o">=</span> <span class="nb">id</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="n">_id2obj_dict</span><span class="p">[</span><span class="n">oid</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
<span class="k">return</span> <span class="n">oid</span>
<span class="k">def</span> <span class="nf">id2obj</span><span class="p">(</span><span class="n">oid</span><span class="p">):</span>
<span class="k">return</span> <span class="n">_id2obj_dict</span><span class="p">[</span><span class="n">oid</span><span class="p">]</span>
</code></pre></div><div class="section" id="finalizer-objects"><h2><span class="yiyi-st" id="yiyi-153">8.8.3.</span><span class="yiyi-st" id="yiyi-154">Finalizer对象</span></h2><p><span class="yiyi-st" id="yiyi-155">使用<a class="reference internal" href="#weakref.finalize" title="weakref.finalize"><code class="xref py py-class docutils literal"><span class="pre">finalize</span></code></a>的主要好处是,它使注册回调变得简单,而不需要保留返回的终结器对象。</span><span class="yiyi-st" id="yiyi-156">实例</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">weakref</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Object</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">pass</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">kenny</span> <span class="o">=</span> <span class="n">Object</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">weakref</span><span class="o">.</span><span class="n">finalize</span><span class="p">(</span><span class="n">kenny</span><span class="p">,</span> <span class="nb">print</span><span class="p">,</span> <span class="s2">"You killed Kenny!"</span><span class="p">)</span>
<span class="go">&lt;finalize object at ...; for 'Object' at ...&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">kenny</span>
<span class="go">You killed Kenny!</span>
</code></pre><p><span class="yiyi-st" id="yiyi-157">终结器也可以直接调用。</span><span class="yiyi-st" id="yiyi-158">然而,终结器将最多调用回调一次。</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">callback</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">):</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">"CALLBACK"</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">obj</span> <span class="o">=</span> <span class="n">Object</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">finalize</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">z</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">assert</span> <span class="n">f</span><span class="o">.</span><span class="n">alive</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">assert</span> <span class="n">f</span><span class="p">()</span> <span class="o">==</span> <span class="mi">6</span>
<span class="go">CALLBACK</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">assert</span> <span class="ow">not</span> <span class="n">f</span><span class="o">.</span><span class="n">alive</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">()</span> <span class="c1"># callback not called because finalizer dead</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">obj</span> <span class="c1"># callback not called because finalizer dead</span>
</code></pre><p><span class="yiyi-st" id="yiyi-159">您可以使用其<a class="reference internal" href="#weakref.finalize.detach" title="weakref.finalize.detach"><code class="xref py py-meth docutils literal"><span class="pre">detach()</span></code></a>方法取消注册终结器。</span><span class="yiyi-st" id="yiyi-160">这会杀死终结器并返回在创建时传递给构造函数的参数。</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">obj</span> <span class="o">=</span> <span class="n">Object</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">finalize</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">z</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>
<span class="go">(&lt;__main__.Object object ...&gt;, &lt;function callback ...&gt;, (1, 2), {'z': 3})</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">newobj</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">_</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">assert</span> <span class="ow">not</span> <span class="n">f</span><span class="o">.</span><span class="n">alive</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">assert</span> <span class="n">newobj</span> <span class="ow">is</span> <span class="n">obj</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">assert</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">==</span> <span class="mi">6</span>
<span class="go">CALLBACK</span>
</code></pre><p><span class="yiyi-st" id="yiyi-161">除非您将<a class="reference internal" href="#weakref.finalize.atexit" title="weakref.finalize.atexit"><code class="xref py py-attr docutils literal"><span class="pre">atexit</span></code></a>属性设置为<a class="reference internal" href="constants.html#False" title="False"><code class="xref py py-const docutils literal"><span class="pre">False</span></code></a>,否则程序退出时将调用终结器,如果它仍然存在。</span><span class="yiyi-st" id="yiyi-162">实例</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">obj</span> <span class="o">=</span> <span class="n">Object</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">weakref</span><span class="o">.</span><span class="n">finalize</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="nb">print</span><span class="p">,</span> <span class="s2">"obj dead or exiting"</span><span class="p">)</span>
<span class="go">&lt;finalize object at ...; for 'Object' at ...&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">exit</span><span class="p">()</span>
<span class="go">obj dead or exiting</span>
</code></pre></div><div class="section" id="comparing-finalizers-with-del-methods"><h2><span class="yiyi-st" id="yiyi-163">8.8.4.</span><span class="yiyi-st" id="yiyi-164">比较终结符与<a class="reference internal" href="../reference/datamodel.html#object.__del__" title="object.__del__"><code class="xref py py-meth docutils literal"><span class="pre">__del__()</span></code></a>方法</span></h2><p><span class="yiyi-st" id="yiyi-165">假设我们要创建一个类,其实例代表临时目录。</span><span class="yiyi-st" id="yiyi-166">当以下第一个事件发生时,应删除目录及其内容:</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-167">对象是垃圾回收,</span></li><li><span class="yiyi-st" id="yiyi-168">调用对象的<code class="xref py py-meth docutils literal"><span class="pre">remove()</span></code>方法,或</span></li><li><span class="yiyi-st" id="yiyi-169">程序退出。</span></li></ul><p><span class="yiyi-st" id="yiyi-170">我们可以尝试使用<a class="reference internal" href="../reference/datamodel.html#object.__del__" title="object.__del__"><code class="xref py py-meth docutils literal"><span class="pre">__del__()</span></code></a>方法实现类,如下所示:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">TempDir</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">mkdtemp</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="kc">None</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">removed</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">__del__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-171">Starting with Python 3.4, <a class="reference internal" href="../reference/datamodel.html#object.__del__" title="object.__del__"><code class="xref py py-meth docutils literal"><span class="pre">__del__()</span></code></a> methods no longer prevent reference cycles from being garbage collected, and module globals are no longer forced to <a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a> during <a class="reference internal" href="../glossary.html#term-interpreter-shutdown"><span class="xref std std-term">interpreter shutdown</span></a>. </span><span class="yiyi-st" id="yiyi-172">所以这个代码应该工作没有任何问题在CPython。</span></p><p><span class="yiyi-st" id="yiyi-173">然而,处理<a class="reference internal" href="../reference/datamodel.html#object.__del__" title="object.__del__"><code class="xref py py-meth docutils literal"><span class="pre">__del__()</span></code></a>方法是众所周知的实现特定的,因为它取决于解释器的垃圾收集器实现的内部细节。</span></p><p><span class="yiyi-st" id="yiyi-174">一个更鲁棒的替代方法是定义一个finalizer它只引用它所需要的特定函数和对象而不是访问对象的完整状态</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">TempDir</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">mkdtemp</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_finalizer</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">finalize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_finalizer</span><span class="p">()</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">removed</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_finalizer</span><span class="o">.</span><span class="n">alive</span>
</code></pre><p><span class="yiyi-st" id="yiyi-175">像这样定义,我们的终结器只接收对它需要的细节的引用,以适当地清理目录。</span><span class="yiyi-st" id="yiyi-176">如果对象永远不会被垃圾收集,终结器仍将在退出时被调用。</span></p><p><span class="yiyi-st" id="yiyi-177">基于weakref的终结器的另一个优点是它们可以用于为定义由第三方控制的类注册终结器例如当模块卸载时运行代码</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">weakref</span><span class="o">,</span> <span class="nn">sys</span>
<span class="k">def</span> <span class="nf">unloading_module</span><span class="p">():</span>
<span class="c1"># implicit reference to the module globals from the function body</span>
<span class="n">weakref</span><span class="o">.</span><span class="n">finalize</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">__name__</span><span class="p">],</span> <span class="n">unloading_module</span><span class="p">)</span>
</code></pre><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-178">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-179">如果你在程序退出时在守护线程中创建一个终结器对象,那么终结器有可能在退出时不被调用。</span><span class="yiyi-st" id="yiyi-180">然而在daemonic线程<a class="reference internal" href="atexit.html#atexit.register" title="atexit.register"><code class="xref py py-func docutils literal"><span class="pre">atexit.register()</span></code></a><code class="docutils literal"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">finally</span> <span class="pre">...</span></code><code class="docutils literal"><span class="pre">与:</span> <span class="pre">...</span></code></span></p></div></div></div></div>