553 lines
35 KiB
HTML
553 lines
35 KiB
HTML
|
|
|||
|
<!DOCTYPE html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="utf-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<meta name="color-scheme" content="light dark">
|
|||
|
<title>PEP 205 – Weak References | peps.python.org</title>
|
|||
|
<link rel="shortcut icon" href="../_static/py.png">
|
|||
|
<link rel="canonical" href="https://peps.python.org/pep-0205/">
|
|||
|
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
|||
|
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
|||
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
|||
|
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
|||
|
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
|||
|
<meta property="og:title" content='PEP 205 – Weak References | peps.python.org'>
|
|||
|
<meta property="og:description" content="Python Enhancement Proposals (PEPs)">
|
|||
|
<meta property="og:type" content="website">
|
|||
|
<meta property="og:url" content="https://peps.python.org/pep-0205/">
|
|||
|
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
|||
|
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
|||
|
<meta property="og:image:alt" content="Python PEPs">
|
|||
|
<meta property="og:image:width" content="200">
|
|||
|
<meta property="og:image:height" content="200">
|
|||
|
<meta name="description" content="Python Enhancement Proposals (PEPs)">
|
|||
|
<meta name="theme-color" content="#3776ab">
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
|||
|
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Following system colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<circle cx="12" cy="12" r="9"></circle>
|
|||
|
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Selected dark colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|||
|
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Selected light colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<circle cx="12" cy="12" r="5"></circle>
|
|||
|
<line x1="12" y1="1" x2="12" y2="3"></line>
|
|||
|
<line x1="12" y1="21" x2="12" y2="23"></line>
|
|||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
|||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
|||
|
<line x1="1" y1="12" x2="3" y2="12"></line>
|
|||
|
<line x1="21" y1="12" x2="23" y2="12"></line>
|
|||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
|||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
</svg>
|
|||
|
<script>
|
|||
|
|
|||
|
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
|||
|
</script>
|
|||
|
<section id="pep-page-section">
|
|||
|
<header>
|
|||
|
<h1>Python Enhancement Proposals</h1>
|
|||
|
<ul class="breadcrumbs">
|
|||
|
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
|||
|
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
|||
|
<li>PEP 205</li>
|
|||
|
</ul>
|
|||
|
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
|||
|
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
|||
|
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
|||
|
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
|||
|
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
|||
|
</button>
|
|||
|
</header>
|
|||
|
<article>
|
|||
|
<section id="pep-content">
|
|||
|
<h1 class="page-title">PEP 205 – Weak References</h1>
|
|||
|
<dl class="rfc2822 field-list simple">
|
|||
|
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">Fred L. Drake, Jr. <fred at fdrake.net></dd>
|
|||
|
<dt class="field-even">Status<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
|
|||
|
<dt class="field-odd">Type<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
|||
|
<dt class="field-even">Created<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">14-Jul-2000</dd>
|
|||
|
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">2.1</dd>
|
|||
|
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">11-Jan-2001</dd>
|
|||
|
</dl>
|
|||
|
<hr class="docutils" />
|
|||
|
<section id="contents">
|
|||
|
<details><summary>Table of Contents</summary><ul class="simple">
|
|||
|
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
|||
|
<li><a class="reference internal" href="#caches-weak-dictionaries">Caches (weak dictionaries)</a></li>
|
|||
|
<li><a class="reference internal" href="#circular-references">Circular references</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#aspects-of-the-solution-space">Aspects of the Solution Space</a><ul>
|
|||
|
<li><a class="reference internal" href="#invalidation">Invalidation</a></li>
|
|||
|
<li><a class="reference internal" href="#presentation">Presentation</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#proposed-solution">Proposed Solution</a></li>
|
|||
|
<li><a class="reference internal" href="#implementation-strategy">Implementation Strategy</a></li>
|
|||
|
<li><a class="reference internal" href="#possible-applications">Possible Applications</a></li>
|
|||
|
<li><a class="reference internal" href="#previous-weak-reference-work-in-python">Previous Weak Reference Work in Python</a></li>
|
|||
|
<li><a class="reference internal" href="#weak-references-in-java">Weak References in Java</a></li>
|
|||
|
<li><a class="reference internal" href="#appendix-dianne-hackborn-s-vref-proposal-1995">Appendix – Dianne Hackborn’s vref proposal (1995)</a><ul>
|
|||
|
<li><a class="reference internal" href="#proposal-virtual-references">Proposal: Virtual References</a></li>
|
|||
|
<li><a class="reference internal" href="#pointer-semantics">Pointer semantics</a></li>
|
|||
|
<li><a class="reference internal" href="#proxy-semantics">Proxy semantics</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
|||
|
</ul>
|
|||
|
</details></section>
|
|||
|
<section id="motivation">
|
|||
|
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
|||
|
<p>There are two basic applications for weak references which have
|
|||
|
been noted by Python programmers: object caches and reduction of
|
|||
|
pain from circular references.</p>
|
|||
|
<section id="caches-weak-dictionaries">
|
|||
|
<h3><a class="toc-backref" href="#caches-weak-dictionaries" role="doc-backlink">Caches (weak dictionaries)</a></h3>
|
|||
|
<p>There is a need to allow objects to be maintained that represent
|
|||
|
external state, mapping a single instance to the external
|
|||
|
reality, where allowing multiple instances to be mapped to the
|
|||
|
same external resource would create unnecessary difficulty
|
|||
|
maintaining synchronization among instances. In these cases,
|
|||
|
a common idiom is to support a cache of instances; a factory
|
|||
|
function is used to return either a new or existing instance.</p>
|
|||
|
<p>The difficulty in this approach is that one of two things must
|
|||
|
be tolerated: either the cache grows without bound, or there
|
|||
|
needs to be explicit management of the cache elsewhere in the
|
|||
|
application. The later can be very tedious and leads to more
|
|||
|
code than is really necessary to solve the problem at hand,
|
|||
|
and the former can be unacceptable for long-running processes
|
|||
|
or even relatively short processes with substantial memory
|
|||
|
requirements.</p>
|
|||
|
<ul class="simple">
|
|||
|
<li>External objects that need to be represented by a single
|
|||
|
instance, no matter how many internal users there are. This
|
|||
|
can be useful for representing files that need to be written
|
|||
|
back to disk in whole rather than locked & modified for
|
|||
|
every use.</li>
|
|||
|
<li>Objects that are expensive to create, but may be needed by
|
|||
|
multiple internal consumers. Similar to the first case, but
|
|||
|
not necessarily bound to external resources, and possibly
|
|||
|
not an issue for shared state. Weak references are only
|
|||
|
useful in this case if there is some flavor of “soft”
|
|||
|
references or if there is a high likelihood that users of
|
|||
|
individual objects will overlap in lifespan.</li>
|
|||
|
</ul>
|
|||
|
</section>
|
|||
|
<section id="circular-references">
|
|||
|
<h3><a class="toc-backref" href="#circular-references" role="doc-backlink">Circular references</a></h3>
|
|||
|
<ul class="simple">
|
|||
|
<li>DOMs require a huge amount of circular (to parent & document
|
|||
|
nodes) references, but these could be eliminated using a weak
|
|||
|
dictionary mapping from each node to its parent. This
|
|||
|
might be especially useful in the context of something like
|
|||
|
<code class="docutils literal notranslate"><span class="pre">xml.dom.pulldom</span></code>, allowing the <code class="docutils literal notranslate"><span class="pre">.unlink()</span></code> operation to become
|
|||
|
a no-op.</li>
|
|||
|
</ul>
|
|||
|
<p>This proposal is divided into the following sections:</p>
|
|||
|
<ul class="simple">
|
|||
|
<li>Proposed Solution</li>
|
|||
|
<li>Implementation Strategy</li>
|
|||
|
<li>Possible Applications</li>
|
|||
|
<li>Previous Weak Reference Work in Python</li>
|
|||
|
<li>Weak References in Java</li>
|
|||
|
</ul>
|
|||
|
<p>The full text of one early proposal is included as an appendix
|
|||
|
since it does not appear to be available on the net.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="aspects-of-the-solution-space">
|
|||
|
<h2><a class="toc-backref" href="#aspects-of-the-solution-space" role="doc-backlink">Aspects of the Solution Space</a></h2>
|
|||
|
<p>There are two distinct aspects to the weak references problem:</p>
|
|||
|
<ul class="simple">
|
|||
|
<li>Invalidation of weak references</li>
|
|||
|
<li>Presentation of weak references to Python code</li>
|
|||
|
</ul>
|
|||
|
<section id="invalidation">
|
|||
|
<h3><a class="toc-backref" href="#invalidation" role="doc-backlink">Invalidation</a></h3>
|
|||
|
<p>Past approaches to weak reference invalidation have often hinged
|
|||
|
on storing a strong reference and being able to examine all the
|
|||
|
instances of weak reference objects, and invalidating them when
|
|||
|
the reference count of their referent goes to one (indicating that
|
|||
|
the reference stored by the weak reference is the last remaining
|
|||
|
reference). This has the advantage that the memory management
|
|||
|
machinery in Python need not change, and that any type can be
|
|||
|
weakly referenced.</p>
|
|||
|
<p>The disadvantage of this approach to invalidation is that it
|
|||
|
assumes that the management of the weak references is called
|
|||
|
sufficiently frequently that weakly-referenced objects are noticed
|
|||
|
within a reasonably short time frame; since this means a scan over
|
|||
|
some data structure to invalidate references, an operation which
|
|||
|
is O(N) on the number of weakly referenced objects, this is not
|
|||
|
effectively amortized for any single object which is weakly
|
|||
|
referenced. This also assumes that the application is calling
|
|||
|
into code which handles weakly-referenced objects with some
|
|||
|
frequency, which makes weak-references less attractive for library
|
|||
|
code.</p>
|
|||
|
<p>An alternate approach to invalidation is that the de-allocation
|
|||
|
code to be aware of the possibility of weak references and make a
|
|||
|
specific call into the weak-reference management code to all
|
|||
|
invalidation whenever an object is deallocated. This requires a
|
|||
|
change in the tp_dealloc handler for weakly-referencable objects;
|
|||
|
an additional call is needed at the “top” of the handler for
|
|||
|
objects which support weak-referencing, and an efficient way to
|
|||
|
map from an object to a chain of weak references for that object
|
|||
|
is needed as well.</p>
|
|||
|
</section>
|
|||
|
<section id="presentation">
|
|||
|
<h3><a class="toc-backref" href="#presentation" role="doc-backlink">Presentation</a></h3>
|
|||
|
<p>Two ways that weak references are presented to the Python layer
|
|||
|
have been as explicit reference objects upon which some operation
|
|||
|
is required in order to retrieve a usable reference to the
|
|||
|
underlying object, and proxy objects which masquerade as the
|
|||
|
original objects as much as possible.</p>
|
|||
|
<p>Reference objects are easy to work with when some additional layer
|
|||
|
of object management is being added in Python; references can be
|
|||
|
checked for liveness explicitly, without having to invoke
|
|||
|
operations on the referents and catching some special exception
|
|||
|
raised when an invalid weak reference is used.</p>
|
|||
|
<p>However, a number of users favor the proxy approach simply because
|
|||
|
the weak reference looks so much like the original object.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="proposed-solution">
|
|||
|
<h2><a class="toc-backref" href="#proposed-solution" role="doc-backlink">Proposed Solution</a></h2>
|
|||
|
<p>Weak references should be able to point to any Python object that
|
|||
|
may have substantial memory size (directly or indirectly), or hold
|
|||
|
references to external resources (database connections, open
|
|||
|
files, etc.).</p>
|
|||
|
<p>A new module, weakref, will contain new functions used to create
|
|||
|
weak references. <code class="docutils literal notranslate"><span class="pre">weakref.ref()</span></code> will create a “weak reference
|
|||
|
object” and optionally attach a callback which will be called when
|
|||
|
the object is about to be finalized. <code class="docutils literal notranslate"><span class="pre">weakref.mapping()</span></code> will
|
|||
|
create a “weak dictionary”. A third function, <code class="docutils literal notranslate"><span class="pre">weakref.proxy()</span></code>,
|
|||
|
will create a proxy object that behaves somewhat like the original
|
|||
|
object.</p>
|
|||
|
<p>A weak reference object will allow access to the referenced object
|
|||
|
if it hasn’t been collected and to determine if the object still
|
|||
|
exists in memory. Retrieving the referent is done by calling the
|
|||
|
reference object. If the referent is no longer alive, this will
|
|||
|
return None instead.</p>
|
|||
|
<p>A weak dictionary maps arbitrary keys to values, but does not own
|
|||
|
a reference to the values. When the values are finalized, the
|
|||
|
(key, value) pairs for which it is a value are removed from all
|
|||
|
the mappings containing such pairs. Like dictionaries, weak
|
|||
|
dictionaries are not hashable.</p>
|
|||
|
<p>Proxy objects are weak references that attempt to behave like the
|
|||
|
object they proxy, as much as they can. Regardless of the
|
|||
|
underlying type, proxies are not hashable since their ability to
|
|||
|
act as a weak reference relies on a fundamental mutability that
|
|||
|
will cause failures when used as dictionary keys – even if the
|
|||
|
proper hash value is computed before the referent dies, the
|
|||
|
resulting proxy cannot be used as a dictionary key since it cannot
|
|||
|
be compared once the referent has expired, and comparability is
|
|||
|
necessary for dictionary keys. Operations on proxy objects after
|
|||
|
the referent dies cause weakref.ReferenceError to be raised in
|
|||
|
most cases. “is” comparisons, <code class="docutils literal notranslate"><span class="pre">type()</span></code>, and <code class="docutils literal notranslate"><span class="pre">id()</span></code> will continue to
|
|||
|
work, but always refer to the proxy and not the referent.</p>
|
|||
|
<p>The callbacks registered with weak references must accept a single
|
|||
|
parameter, which will be the weak reference or proxy object
|
|||
|
itself. The object cannot be accessed or resurrected in the
|
|||
|
callback.</p>
|
|||
|
</section>
|
|||
|
<section id="implementation-strategy">
|
|||
|
<h2><a class="toc-backref" href="#implementation-strategy" role="doc-backlink">Implementation Strategy</a></h2>
|
|||
|
<p>The implementation of weak references will include a list of
|
|||
|
reference containers that must be cleared for each weakly-referencable
|
|||
|
object. If the reference is from a weak dictionary,
|
|||
|
the dictionary entry is cleared first. Then, any associated
|
|||
|
callback is called with the object passed as a parameter. Once
|
|||
|
all callbacks have been called, the object is finalized and
|
|||
|
deallocated.</p>
|
|||
|
<p>Many built-in types will participate in the weak-reference
|
|||
|
management, and any extension type can elect to do so. The type
|
|||
|
structure will contain an additional field which provides an
|
|||
|
offset into the instance structure which contains a list of weak
|
|||
|
reference structures. If the value of the field is <= 0, the
|
|||
|
object does not participate. In this case, <code class="docutils literal notranslate"><span class="pre">weakref.ref()</span></code>,
|
|||
|
<code class="docutils literal notranslate"><span class="pre"><weakdict>.__setitem__()</span></code> and <code class="docutils literal notranslate"><span class="pre">.setdefault()</span></code>, and item assignment will
|
|||
|
raise <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>. If the value of the field is > 0, a new weak
|
|||
|
reference can be generated and added to the list.</p>
|
|||
|
<p>This approach is taken to allow arbitrary extension types to
|
|||
|
participate, without taking a memory hit for numbers or other
|
|||
|
small types.</p>
|
|||
|
<p>Standard types which support weak references include instances,
|
|||
|
functions, and bound & unbound methods. With the addition of
|
|||
|
class types (“new-style classes”) in Python 2.2, types grew
|
|||
|
support for weak references. Instances of class types are weakly
|
|||
|
referencable if they have a base type which is weakly referencable,
|
|||
|
the class not specify <code class="docutils literal notranslate"><span class="pre">__slots__</span></code>, or a slot is named <code class="docutils literal notranslate"><span class="pre">__weakref__</span></code>.
|
|||
|
Generators also support weak references.</p>
|
|||
|
</section>
|
|||
|
<section id="possible-applications">
|
|||
|
<h2><a class="toc-backref" href="#possible-applications" role="doc-backlink">Possible Applications</a></h2>
|
|||
|
<p>PyGTK+ bindings?</p>
|
|||
|
<p>Tkinter – could avoid circular references by using weak
|
|||
|
references from widgets to their parents. Objects won’t be
|
|||
|
discarded any sooner in the typical case, but there won’t be so
|
|||
|
much dependence on the programmer calling <code class="docutils literal notranslate"><span class="pre">.destroy()</span></code> before
|
|||
|
releasing a reference. This would mostly benefit long-running
|
|||
|
applications.</p>
|
|||
|
<p>DOM trees.</p>
|
|||
|
</section>
|
|||
|
<section id="previous-weak-reference-work-in-python">
|
|||
|
<h2><a class="toc-backref" href="#previous-weak-reference-work-in-python" role="doc-backlink">Previous Weak Reference Work in Python</a></h2>
|
|||
|
<p>Dianne Hackborn has proposed something called “virtual references”.
|
|||
|
‘vref’ objects are very similar to java.lang.ref.WeakReference
|
|||
|
objects, except there is no equivalent to the invalidation
|
|||
|
queues. Implementing a “weak dictionary” would be just as
|
|||
|
difficult as using only weak references (without the invalidation
|
|||
|
queue) in Java. Information on this has disappeared from the Web,
|
|||
|
but is included below as an Appendix.</p>
|
|||
|
<p>Marc-André Lemburg’s mx.Proxy package:</p>
|
|||
|
<blockquote>
|
|||
|
<div><a class="reference external" href="http://www.lemburg.com/files/python/mxProxy.html">http://www.lemburg.com/files/python/mxProxy.html</a></div></blockquote>
|
|||
|
<p>The weakdict module by Dieter Maurer is implemented in C and
|
|||
|
Python. It appears that the Web pages have not been updated since
|
|||
|
Python 1.5.2a, so I’m not yet sure if the implementation is
|
|||
|
compatible with Python 2.0.</p>
|
|||
|
<blockquote>
|
|||
|
<div><a class="reference external" href="http://www.handshake.de/~dieter/weakdict.html">http://www.handshake.de/~dieter/weakdict.html</a></div></blockquote>
|
|||
|
<p>PyWeakReference by Alex Shindich:</p>
|
|||
|
<blockquote>
|
|||
|
<div><a class="reference external" href="http://sourceforge.net/projects/pyweakreference/">http://sourceforge.net/projects/pyweakreference/</a></div></blockquote>
|
|||
|
<p>Eric Tiedemann has a weak dictionary implementation:</p>
|
|||
|
<blockquote>
|
|||
|
<div><a class="reference external" href="http://www.hyperreal.org/~est/python/weak/">http://www.hyperreal.org/~est/python/weak/</a></div></blockquote>
|
|||
|
</section>
|
|||
|
<section id="weak-references-in-java">
|
|||
|
<h2><a class="toc-backref" href="#weak-references-in-java" role="doc-backlink">Weak References in Java</a></h2>
|
|||
|
<p><a class="reference external" href="http://java.sun.com/j2se/1.3/docs/api/java/lang/ref/package-summary.html">http://java.sun.com/j2se/1.3/docs/api/java/lang/ref/package-summary.html</a></p>
|
|||
|
<p>Java provides three forms of weak references, and one interesting
|
|||
|
helper class. The three forms are called “weak”, “soft”, and
|
|||
|
“phantom” references. The relevant classes are defined in the
|
|||
|
java.lang.ref package.</p>
|
|||
|
<p>For each of the reference types, there is an option to add the
|
|||
|
reference to a queue when it is invalidated by the memory
|
|||
|
allocator. The primary purpose of this facility seems to be that
|
|||
|
it allows larger structures to be composed to incorporate
|
|||
|
weak-reference semantics without having to impose substantial
|
|||
|
additional locking requirements. For instance, it would not be
|
|||
|
difficult to use this facility to create a “weak” hash table which
|
|||
|
removes keys and referents when a reference is no longer used
|
|||
|
elsewhere. Using weak references for the objects without some
|
|||
|
sort of notification queue for invalidations leads to much more
|
|||
|
tedious implementation of the various operations required on hash
|
|||
|
tables. This can be a performance bottleneck if deallocations of
|
|||
|
the stored objects are infrequent.</p>
|
|||
|
<p>Java’s “weak” references are most like Dianne Hackborn’s old vref
|
|||
|
proposal: a reference object refers to a single Python object,
|
|||
|
but does not own a reference to that object. When that object is
|
|||
|
deallocated, the reference object is invalidated. Users of the
|
|||
|
reference object can easily determine that the reference has been
|
|||
|
invalidated, or a NullObjectDereferenceError can be raised when
|
|||
|
an attempt is made to use the referred-to object.</p>
|
|||
|
<p>The “soft” references are similar, but are not invalidated as soon
|
|||
|
as all other references to the referred-to object have been
|
|||
|
released. The “soft” reference does own a reference, but allows
|
|||
|
the memory allocator to free the referent if the memory is needed
|
|||
|
elsewhere. It is not clear whether this means soft references are
|
|||
|
released before the <code class="docutils literal notranslate"><span class="pre">malloc()</span></code> implementation calls <code class="docutils literal notranslate"><span class="pre">sbrk()</span></code> or its
|
|||
|
equivalent, or if soft references are only cleared when <code class="docutils literal notranslate"><span class="pre">malloc()</span></code>
|
|||
|
returns <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p>
|
|||
|
<p>“Phantom” references are a little different; unlike weak and soft
|
|||
|
references, the referent is not cleared when the reference is
|
|||
|
added to its queue. When all phantom references for an object
|
|||
|
are dequeued, the object is cleared. This can be used to keep an
|
|||
|
object alive until some additional cleanup is performed which
|
|||
|
needs to happen before the objects <code class="docutils literal notranslate"><span class="pre">.finalize()</span></code> method is called.</p>
|
|||
|
<p>Unlike the other two reference types, “phantom” references must be
|
|||
|
associated with an invalidation queue.</p>
|
|||
|
</section>
|
|||
|
<section id="appendix-dianne-hackborn-s-vref-proposal-1995">
|
|||
|
<h2><a class="toc-backref" href="#appendix-dianne-hackborn-s-vref-proposal-1995" role="doc-backlink">Appendix – Dianne Hackborn’s vref proposal (1995)</a></h2>
|
|||
|
<p>[This has been indented and paragraphs reflowed, but there have be
|
|||
|
no content changes. –Fred]</p>
|
|||
|
<section id="proposal-virtual-references">
|
|||
|
<h3><a class="toc-backref" href="#proposal-virtual-references" role="doc-backlink">Proposal: Virtual References</a></h3>
|
|||
|
<p>In an attempt to partly address the recurring discussion
|
|||
|
concerning reference counting vs. garbage collection, I would like
|
|||
|
to propose an extension to Python which should help in the
|
|||
|
creation of “well structured” cyclic graphs. In particular, it
|
|||
|
should allow at least trees with parent back-pointers and
|
|||
|
doubly-linked lists to be created without worry about cycles.</p>
|
|||
|
<p>The basic mechanism I’d like to propose is that of a “virtual
|
|||
|
reference,” or a “vref” from here on out. A vref is essentially a
|
|||
|
handle on an object that does not increment the object’s reference
|
|||
|
count. This means that holding a vref on an object will not keep
|
|||
|
the object from being destroyed. This would allow the Python
|
|||
|
programmer, for example, to create the aforementioned tree
|
|||
|
structure, which is automatically destroyed when it
|
|||
|
is no longer in use – by making all of the parent back-references
|
|||
|
into vrefs, they no longer create reference cycles which keep the
|
|||
|
tree from being destroyed.</p>
|
|||
|
<p>In order to implement this mechanism, the Python core must ensure
|
|||
|
that no -real- pointers are ever left referencing objects that no
|
|||
|
longer exist. The implementation I would like to propose involves
|
|||
|
two basic additions to the current Python system:</p>
|
|||
|
<ol class="arabic simple">
|
|||
|
<li>A new “vref” type, through which the Python programmer creates
|
|||
|
and manipulates virtual references. Internally, it is
|
|||
|
basically a C-level Python object with a pointer to the Python
|
|||
|
object it is a reference to. Unlike all other Python code,
|
|||
|
however, it does not change the reference count of this object.
|
|||
|
In addition, it includes two pointers to implement a
|
|||
|
doubly-linked list, which is used below.</li>
|
|||
|
<li>The addition of a new field to the basic Python object
|
|||
|
[<code class="docutils literal notranslate"><span class="pre">PyObject_Head</span></code> in object.h], which is either <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, or points to
|
|||
|
the head of a list of all vref objects that reference it. When
|
|||
|
a vref object attaches itself to another object, it adds itself
|
|||
|
to this linked list. Then, if an object with any vrefs on it
|
|||
|
is deallocated, it may walk this list and ensure that all of
|
|||
|
the vrefs on it point to some safe value, e.g. Nothing.</li>
|
|||
|
</ol>
|
|||
|
<p>This implementation should hopefully have a minimal impact on the
|
|||
|
current Python core – when no vrefs exist, it should only add one
|
|||
|
pointer to all objects, and a check for a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> pointer every time
|
|||
|
an object is deallocated.</p>
|
|||
|
<p>Back at the Python language level, I have considered two possible
|
|||
|
semantics for the vref object –</p>
|
|||
|
</section>
|
|||
|
<section id="pointer-semantics">
|
|||
|
<h3><a class="toc-backref" href="#pointer-semantics" role="doc-backlink">Pointer semantics</a></h3>
|
|||
|
<p>In this model, a vref behaves essentially like a Python-level
|
|||
|
pointer; the Python program must explicitly dereference the vref
|
|||
|
to manipulate the actual object it references.</p>
|
|||
|
<p>An example vref module using this model could include the
|
|||
|
function “new”; When used as ‘MyVref = vref.new(MyObject)’, it
|
|||
|
returns a new vref object such that <code class="docutils literal notranslate"><span class="pre">MyVref.object</span> <span class="pre">==</span> <span class="pre">MyObject</span></code>.
|
|||
|
<code class="docutils literal notranslate"><span class="pre">MyVref.object</span></code> would then change to Nothing if
|
|||
|
<code class="docutils literal notranslate"><span class="pre">MyObject</span></code> is ever deallocated.</p>
|
|||
|
<p>For a concrete example, we may introduce some new C-style syntax:</p>
|
|||
|
<ul class="simple">
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">&</span></code> – unary operator, creates a vref on an object, same as <code class="docutils literal notranslate"><span class="pre">vref.new()</span></code>.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">*</span></code> – unary operator, dereference a vref, same as <code class="docutils literal notranslate"><span class="pre">VrefObject.object</span></code>.</li>
|
|||
|
</ul>
|
|||
|
<p>We can then define:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.</span> <span class="nb">type</span><span class="p">(</span><span class="o">&</span><span class="n">MyObject</span><span class="p">)</span> <span class="o">==</span> <span class="n">vref</span><span class="o">.</span><span class="n">VrefType</span>
|
|||
|
<span class="mf">2.</span> <span class="o">*</span><span class="p">(</span><span class="o">&</span><span class="n">MyObject</span><span class="p">)</span> <span class="o">==</span> <span class="n">MyObject</span>
|
|||
|
<span class="mf">3.</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">&</span><span class="n">MyObject</span><span class="p">))</span><span class="o">.</span><span class="n">attr</span> <span class="o">==</span> <span class="n">MyObject</span><span class="o">.</span><span class="n">attr</span>
|
|||
|
<span class="mf">4.</span> <span class="o">&&</span><span class="n">MyObject</span> <span class="o">==</span> <span class="n">Nothing</span>
|
|||
|
<span class="mf">5.</span> <span class="o">*</span><span class="n">MyObject</span> <span class="o">-></span> <span class="n">exception</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Rule #4 is subtle, but comes about because we have made a vref
|
|||
|
to (a vref with no real references). Thus the outer vref is
|
|||
|
cleared to Nothing when the inner one inevitably disappears.</p>
|
|||
|
</section>
|
|||
|
<section id="proxy-semantics">
|
|||
|
<h3><a class="toc-backref" href="#proxy-semantics" role="doc-backlink">Proxy semantics</a></h3>
|
|||
|
<p>In this model, the Python programmer manipulates vref objects
|
|||
|
just as if she were manipulating the object it is a reference
|
|||
|
of. This is accomplished by implementing the vref so that all
|
|||
|
operations on it are redirected to its referenced object. With
|
|||
|
this model, the dereference operator (*) no longer makes sense;
|
|||
|
instead, we have only the reference operator (&), and define:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.</span> <span class="nb">type</span><span class="p">(</span><span class="o">&</span><span class="n">MyObject</span><span class="p">)</span> <span class="o">==</span> <span class="nb">type</span><span class="p">(</span><span class="n">MyObject</span><span class="p">)</span>
|
|||
|
<span class="mf">2.</span> <span class="o">&</span><span class="n">MyObject</span> <span class="o">==</span> <span class="n">MyObject</span>
|
|||
|
<span class="mf">3.</span> <span class="p">(</span><span class="o">&</span><span class="n">MyObject</span><span class="p">)</span><span class="o">.</span><span class="n">attr</span> <span class="o">==</span> <span class="n">MyObject</span><span class="o">.</span><span class="n">attr</span>
|
|||
|
<span class="mf">4.</span> <span class="o">&&</span><span class="n">MyObject</span> <span class="o">==</span> <span class="n">MyObject</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Again, rule #4 is important – here, the outer vref is in fact a
|
|||
|
reference to the original object, and -not- the inner vref.
|
|||
|
This is because all operations applied to a vref actually apply
|
|||
|
to its object, so that creating a vref of a vref actually
|
|||
|
results in creating a vref of the latter’s object.</p>
|
|||
|
<p>The first, pointer semantics, has the advantage that it would be
|
|||
|
very easy to implement; the vref type is extremely simple,
|
|||
|
requiring at minimum a single attribute, object, and a function to
|
|||
|
create a reference.</p>
|
|||
|
<p>However, I really like the proxy semantics. Not only does it put
|
|||
|
less of a burden on the Python programmer, but it allows you to do
|
|||
|
nice things like use a vref anywhere you would use the actual
|
|||
|
object. Unfortunately, it would probably an extreme pain, if not
|
|||
|
practically impossible, to implement in the current Python
|
|||
|
implementation. I do have some thoughts, though, on how to do
|
|||
|
this, if it seems interesting; one possibility is to introduce new
|
|||
|
type-checking functions which handle the vref. This would
|
|||
|
hopefully older C modules which don’t expect vrefs to simply
|
|||
|
return a type error, until they can be fixed.</p>
|
|||
|
<p>Finally, there are some other additional capabilities that this
|
|||
|
system could provide. One that seems particularly interesting to
|
|||
|
me involves allowing the Python programmer to add “destructor”
|
|||
|
function to a vref – this Python function would be called
|
|||
|
immediately prior to the referenced object being deallocated,
|
|||
|
allowing a Python program to invisibly attach itself to another
|
|||
|
object and watch for it to disappear. This seems neat, though I
|
|||
|
haven’t actually come up with any practical uses for it, yet… :)</p>
|
|||
|
<p>– Dianne</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="copyright">
|
|||
|
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
|||
|
<p>This document has been placed in the public domain.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<hr class="docutils" />
|
|||
|
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0205.rst">https://github.com/python/peps/blob/main/peps/pep-0205.rst</a></p>
|
|||
|
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0205.rst">2023-09-09 17:39:29 GMT</a></p>
|
|||
|
|
|||
|
</article>
|
|||
|
<nav id="pep-sidebar">
|
|||
|
<h2>Contents</h2>
|
|||
|
<ul>
|
|||
|
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
|||
|
<li><a class="reference internal" href="#caches-weak-dictionaries">Caches (weak dictionaries)</a></li>
|
|||
|
<li><a class="reference internal" href="#circular-references">Circular references</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#aspects-of-the-solution-space">Aspects of the Solution Space</a><ul>
|
|||
|
<li><a class="reference internal" href="#invalidation">Invalidation</a></li>
|
|||
|
<li><a class="reference internal" href="#presentation">Presentation</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#proposed-solution">Proposed Solution</a></li>
|
|||
|
<li><a class="reference internal" href="#implementation-strategy">Implementation Strategy</a></li>
|
|||
|
<li><a class="reference internal" href="#possible-applications">Possible Applications</a></li>
|
|||
|
<li><a class="reference internal" href="#previous-weak-reference-work-in-python">Previous Weak Reference Work in Python</a></li>
|
|||
|
<li><a class="reference internal" href="#weak-references-in-java">Weak References in Java</a></li>
|
|||
|
<li><a class="reference internal" href="#appendix-dianne-hackborn-s-vref-proposal-1995">Appendix – Dianne Hackborn’s vref proposal (1995)</a><ul>
|
|||
|
<li><a class="reference internal" href="#proposal-virtual-references">Proposal: Virtual References</a></li>
|
|||
|
<li><a class="reference internal" href="#pointer-semantics">Pointer semantics</a></li>
|
|||
|
<li><a class="reference internal" href="#proxy-semantics">Proxy semantics</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<br>
|
|||
|
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0205.rst">Page Source (GitHub)</a>
|
|||
|
</nav>
|
|||
|
</section>
|
|||
|
<script src="../_static/colour_scheme.js"></script>
|
|||
|
<script src="../_static/wrap_tables.js"></script>
|
|||
|
<script src="../_static/sticky_banner.js"></script>
|
|||
|
</body>
|
|||
|
</html>
|