[Python-checkins] cpython: Close #19047: weakref doc cleanups

nick.coghlan python-checkins at python.org
Sun Sep 22 13:27:43 CEST 2013


http://hg.python.org/cpython/rev/caa16423b324
changeset:   85778:caa16423b324
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Sun Sep 22 21:26:30 2013 +1000
summary:
  Close #19047: weakref doc cleanups

- be clear finalizers survive automatically
- update for PEP 442 __del__ changes
- mention module cleanup changes and weakref.finalize in What's New

files:
  Doc/library/weakref.rst |  57 +++++++++++++++++++---------
  Doc/whatsnew/3.4.rst    |  11 ++++-
  2 files changed, 47 insertions(+), 21 deletions(-)


diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst
--- a/Doc/library/weakref.rst
+++ b/Doc/library/weakref.rst
@@ -54,7 +54,8 @@
 :class:`finalize` provides a straight forward way to register a
 cleanup function to be called when an object is garbage collected.
 This is simpler to use than setting up a callback function on a raw
-weak reference.
+weak reference, since the module automatically ensures that the finalizer
+remains alive until the object is collected.
 
 Most programs should find that using one of these weak container types
 or :class:`finalize` is all they need -- it's not usually necessary to
@@ -246,11 +247,14 @@
 .. class:: finalize(obj, func, *args, **kwargs)
 
    Return a callable finalizer object which will be called when *obj*
-   is garbage collected.  A finalizer is *alive* until it is called
-   (either explicitly or at garbage collection), and after that it is
-   *dead*.  Calling a live finalizer returns the result of evaluating
-   ``func(*arg, **kwargs)``, whereas calling a dead finalizer returns
-   :const:`None`.
+   is garbage collected. Unlike an ordinary weak reference, a finalizer is
+   will always survive until the reference object is collected, greatly
+   simplifying lifecycle management.
+
+   A finalizer is considered *alive* until it is called (either explicitly
+   or at garbage collection), and after that it is *dead*.  Calling a live
+   finalizer returns the result of evaluating ``func(*arg, **kwargs)``,
+   whereas calling a dead finalizer returns :const:`None`.
 
    Exceptions raised by finalizer callbacks during garbage collection
    will be shown on the standard error output, but cannot be
@@ -445,8 +449,9 @@
 Finalizer Objects
 -----------------
 
-Often one uses :class:`finalize` to register a callback without
-bothering to keep the returned finalizer object.  For instance
+The main benefit of using :class:`finalize` is that it makes it simple
+to register a callback without needing to preserve the returned finalizer
+object.  For instance
 
     >>> import weakref
     >>> class Object:
@@ -489,7 +494,7 @@
     CALLBACK
 
 Unless you set the :attr:`~finalize.atexit` attribute to
-:const:`False`, a finalizer will be called when the program exit if it
+:const:`False`, a finalizer will be called when the program exits if it
 is still alive.  For instance
 
     >>> obj = Object()
@@ -529,13 +534,18 @@
         def __del__(self):
             self.remove()
 
-This solution has a serious problem: the :meth:`__del__` method may be
-called at shutdown after the :mod:`shutil` module has been cleaned up,
-in which case :attr:`shutil.rmtree` will have been replaced by :const:`None`.
-This will cause the :meth:`__del__` method to fail and the directory
-will not be removed.
+Starting with Python 3.4, :meth:`__del__` methods no longer prevent
+reference cycles from being garbage collected, and module globals are
+no longer forced to :const:`None` during interpreter shutdown. So this
+code should work without any issues on CPython.
 
-Using finalizers we can avoid this problem::
+However, handling of :meth:`__del__` methods is notoriously implementation
+specific, since it depends on how the interpreter's garbage collector
+handles reference cycles and finalizers.
+
+A more robust alternative can be to define a finalizer which only references
+the specific functions and objects that it needs, rather than having access
+to the full state of the object::
 
     class TempDir:
         def __init__(self):
@@ -549,10 +559,19 @@
         def removed(self):
             return not self._finalizer.alive
 
-Defined like this, even if a :class:`TempDir` object is part of a
-reference cycle, that reference cycle can still be garbage collected.
-If the object never gets garbage collected the finalizer will still be
-called at exit.
+Defined like this, our finalizer only receives a reference to the details
+it needs to clean up the directory appropriately. If the object never gets
+garbage collected the finalizer will still be called at exit.
+
+The other advantage of weakref based finalizers is that they can be used to
+register finalizers for classes where the definition is controlled by a
+third party, such as running code when a module is unloaded::
+
+    import weakref, sys
+    def unloading_module():
+        # implicit reference to the module globals from the function body
+    weakref.finalize(sys.modules[__name__], unloading_module)
+
 
 .. note::
 
diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst
--- a/Doc/whatsnew/3.4.rst
+++ b/Doc/whatsnew/3.4.rst
@@ -153,6 +153,10 @@
 with :keyword:`finally` clauses, can be finalized when they are part of a
 reference cycle.
 
+As part of this change, module globals are no longer forcibly set to
+:const:`None` during interpreter shutdown, instead relying on the normal
+operation of the cyclic garbage collector.
+
 .. seealso::
 
    :pep:`442` - Safe object finalization
@@ -416,9 +420,12 @@
 -------
 
 New :class:`~weakref.WeakMethod` class simulates weak references to bound
-methods.
+methods. (Contributed by Antoine Pitrou in :issue:`14631`.)
 
-(Contributed by Antoine Pitrou in :issue:`14631`.)
+New :class:`~weakref.finalize` class makes it possible to register a callback
+to be invoked when an object is garbage collected, without needing to
+carefully manage the lifecycle of the weak reference itself. (Contributed by
+Richard Oudkerk in :issue:`15528`)
 
 
 xml.etree

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list