reSTify PEP 205 (#369)
This commit is contained in:
parent
a49551d35b
commit
d80d5be223
73
pep-0205.txt
73
pep-0205.txt
|
@ -5,17 +5,20 @@ Last-Modified: $Date$
|
|||
Author: Fred L. Drake, Jr. <fdrake@acm.org>
|
||||
Status: Final
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created:
|
||||
Python-Version: 2.1
|
||||
Post-History: 11-Jan-2001
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
||||
There are two basic applications for weak references which have
|
||||
been noted by Python programmers: object caches and reduction of
|
||||
pain from circular references.
|
||||
|
||||
Caches (weak dictionaries)
|
||||
--------------------------
|
||||
|
||||
There is a need to allow objects to be maintained that represent
|
||||
external state, mapping a single instance to the external
|
||||
|
@ -49,12 +52,13 @@ Motivation
|
|||
individual objects will overlap in lifespan.
|
||||
|
||||
Circular references
|
||||
-------------------
|
||||
|
||||
- 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
|
||||
xml.dom.pulldom, allowing the .unlink() operation to become
|
||||
``xml.dom.pulldom``, allowing the ``.unlink()`` operation to become
|
||||
a no-op.
|
||||
|
||||
This proposal is divided into the following sections:
|
||||
|
@ -70,13 +74,15 @@ Motivation
|
|||
|
||||
|
||||
Aspects of the Solution Space
|
||||
=============================
|
||||
|
||||
There are two distinct aspects to the weak references problem:
|
||||
|
||||
- Invalidation of weak references
|
||||
- Presentation of weak references to Python code
|
||||
|
||||
Invalidation:
|
||||
Invalidation
|
||||
------------
|
||||
|
||||
Past approaches to weak reference invalidation have often hinged
|
||||
on storing a strong reference and being able to examine all the
|
||||
|
@ -109,7 +115,8 @@ Aspects of the Solution Space
|
|||
map from an object to a chain of weak references for that object
|
||||
is needed as well.
|
||||
|
||||
Presentation:
|
||||
Presentation
|
||||
------------
|
||||
|
||||
Two ways that weak references are presented to the Python layer
|
||||
have been as explicit reference objects upon which some operation
|
||||
|
@ -128,6 +135,7 @@ Aspects of the Solution Space
|
|||
|
||||
|
||||
Proposed Solution
|
||||
=================
|
||||
|
||||
Weak references should be able to point to any Python object that
|
||||
may have substantial memory size (directly or indirectly), or hold
|
||||
|
@ -135,10 +143,10 @@ Proposed Solution
|
|||
files, etc.).
|
||||
|
||||
A new module, weakref, will contain new functions used to create
|
||||
weak references. weakref.ref() will create a "weak reference
|
||||
weak references. ``weakref.ref()`` will create a "weak reference
|
||||
object" and optionally attach a callback which will be called when
|
||||
the object is about to be finalized. weakref.mapping() will
|
||||
create a "weak dictionary". A third function, weakref.proxy(),
|
||||
the object is about to be finalized. ``weakref.mapping()`` will
|
||||
create a "weak dictionary". A third function, ``weakref.proxy()``,
|
||||
will create a proxy object that behaves somewhat like the original
|
||||
object.
|
||||
|
||||
|
@ -164,7 +172,7 @@ Proposed Solution
|
|||
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, type(), and id() will continue to
|
||||
most cases. "is" comparisons, ``type()``, and ``id()`` will continue to
|
||||
work, but always refer to the proxy and not the referent.
|
||||
|
||||
The callbacks registered with weak references must accept a single
|
||||
|
@ -174,6 +182,7 @@ Proposed Solution
|
|||
|
||||
|
||||
Implementation Strategy
|
||||
=======================
|
||||
|
||||
The implementation of weak references will include a list of
|
||||
reference containers that must be cleared for each weakly-
|
||||
|
@ -188,9 +197,9 @@ Implementation Strategy
|
|||
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, weakref.ref(),
|
||||
<weakdict>.__setitem__() and .setdefault(), and item assignment will
|
||||
raise TypeError. If the value of the field is > 0, a new weak
|
||||
object does not participate. In this case, ``weakref.ref()``,
|
||||
``<weakdict>.__setitem__()`` and ``.setdefault()``, and item assignment will
|
||||
raise ``TypeError``. If the value of the field is > 0, a new weak
|
||||
reference can be generated and added to the list.
|
||||
|
||||
This approach is taken to allow arbitrary extension types to
|
||||
|
@ -202,18 +211,19 @@ Implementation Strategy
|
|||
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 __slots__, or a slot is named __weakref__.
|
||||
the class not specify ``__slots__``, or a slot is named ``__weakref__``.
|
||||
Generators also support weak references.
|
||||
|
||||
|
||||
Possible Applications
|
||||
=====================
|
||||
|
||||
PyGTK+ bindings?
|
||||
|
||||
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 .destroy() before
|
||||
much dependence on the programmer calling ``.destroy()`` before
|
||||
releasing a reference. This would mostly benefit long-running
|
||||
applications.
|
||||
|
||||
|
@ -221,6 +231,7 @@ Possible Applications
|
|||
|
||||
|
||||
Previous Weak Reference Work in Python
|
||||
======================================
|
||||
|
||||
Dianne Hackborn has proposed something called "virtual references".
|
||||
'vref' objects are very similar to java.lang.ref.WeakReference
|
||||
|
@ -251,6 +262,7 @@ Previous Weak Reference Work in Python
|
|||
|
||||
|
||||
Weak References in Java
|
||||
=======================
|
||||
|
||||
http://java.sun.com/j2se/1.3/docs/api/java/lang/ref/package-summary.html
|
||||
|
||||
|
@ -286,27 +298,29 @@ Weak References in Java
|
|||
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 malloc() implementation calls sbrk() or its
|
||||
equivalent, or if soft references are only cleared when malloc()
|
||||
returns NULL.
|
||||
released before the ``malloc()`` implementation calls ``sbrk()`` or its
|
||||
equivalent, or if soft references are only cleared when ``malloc()``
|
||||
returns ``NULL``.
|
||||
|
||||
"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 .finalize() method is called.
|
||||
needs to happen before the objects ``.finalize()`` method is called.
|
||||
|
||||
Unlike the other two reference types, "phantom" references must be
|
||||
associated with an invalidation queue.
|
||||
|
||||
|
||||
Appendix -- Dianne Hackborn's vref proposal (1995)
|
||||
==================================================
|
||||
|
||||
[This has been indented and paragraphs reflowed, but there have be
|
||||
no content changes. --Fred]
|
||||
|
||||
Proposal: Virtual References
|
||||
----------------------------
|
||||
|
||||
In an attempt to partly address the recurring discussion
|
||||
concerning reference counting vs. garbage collection, I would like
|
||||
|
@ -340,7 +354,7 @@ Appendix -- Dianne Hackborn's vref proposal (1995)
|
|||
doubly-linked list, which is used below.
|
||||
|
||||
2. The addition of a new field to the basic Python object
|
||||
[PyObject_Head in object.h], which is either NULL, or points to
|
||||
[``PyObject_Head`` in object.h], which is either ``NULL``, 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
|
||||
|
@ -350,13 +364,14 @@ Appendix -- Dianne Hackborn's vref proposal (1995)
|
|||
|
||||
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 NULL pointer every time
|
||||
pointer to all objects, and a check for a ``NULL`` pointer every time
|
||||
an object is deallocated.
|
||||
|
||||
Back at the Python language level, I have considered two possible
|
||||
semantics for the vref object --
|
||||
|
||||
==> Pointer semantics:
|
||||
Pointer semantics
|
||||
-----------------
|
||||
|
||||
In this model, a vref behaves essentially like a Python-level
|
||||
pointer; the Python program must explicitly dereference the vref
|
||||
|
@ -364,16 +379,16 @@ Appendix -- Dianne Hackborn's vref proposal (1995)
|
|||
|
||||
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 MyVref.object ==
|
||||
MyObject. MyVref.object would then change to Nothing if
|
||||
MyObject is ever deallocated.
|
||||
returns a new vref object such that ``MyVref.object == MyObject``.
|
||||
``MyVref.object`` would then change to Nothing if
|
||||
``MyObject`` is ever deallocated.
|
||||
|
||||
For a concrete example, we may introduce some new C-style syntax:
|
||||
|
||||
& -- unary operator, creates a vref on an object, same as vref.new().
|
||||
* -- unary operator, dereference a vref, same as VrefObject.object.
|
||||
* ``&`` -- unary operator, creates a vref on an object, same as ``vref.new()``.
|
||||
* ``*`` -- unary operator, dereference a vref, same as ``VrefObject.object``.
|
||||
|
||||
We can then define:
|
||||
We can then define::
|
||||
|
||||
1. type(&MyObject) == vref.VrefType
|
||||
2. *(&MyObject) == MyObject
|
||||
|
@ -385,14 +400,15 @@ Appendix -- Dianne Hackborn's vref proposal (1995)
|
|||
to (a vref with no real references). Thus the outer vref is
|
||||
cleared to Nothing when the inner one inevitably disappears.
|
||||
|
||||
==> Proxy semantics:
|
||||
Proxy semantics
|
||||
----------------
|
||||
|
||||
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:
|
||||
instead, we have only the reference operator (&), and define::
|
||||
|
||||
1. type(&MyObject) == type(MyObject)
|
||||
2. &MyObject == MyObject
|
||||
|
@ -434,11 +450,12 @@ Appendix -- Dianne Hackborn's vref proposal (1995)
|
|||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
|
|
Loading…
Reference in New Issue