[Python-Dev] Is there any remaining reason why weakref callbacks shouldn't be able to access the referenced object?

Nick Coghlan ncoghlan at gmail.com
Fri Oct 21 23:32:04 EDT 2016


On 21 October 2016 at 17:09, Nathaniel Smith <njs at pobox.com> wrote:
> But that was 2.4. In the mean time, of course, PEP 442 fixed it so
> that finalizers and weakrefs mix just fine. In fact, weakref callbacks
> are now run *before* __del__ methods [2], so clearly it's now okay for
> arbitrary code to touch the objects during that phase of the GC -- at
> least in principle.
>
> So what I'm wondering is, would anything terrible happen if we started
> passing still-live weakrefs into weakref callbacks, and then clearing
> them afterwards?

The weakref-before-__del__ ordering change in
https://www.python.org/dev/peps/pep-0442/#disposal-of-cyclic-isolates
only applies to cyclic garbage collection,so for normal refcount
driven object cleanup in CPython, the __del__ still happens first:

    >>> class C:
    ...     def __del__(self):
    ...         print("__del__ called")
    ...
    >>> c = C()
    >>> import weakref
    >>> def cb():
    ...     print("weakref callback called")
    ...
    >>> weakref.finalize(c, cb)
    <finalize object at 0x7f4300b710a0; for 'C' at 0x7f42f8ae3470>
    >>> del c
    __del__ called
    weakref callback called

This means the main problem with a strong reference being reachable
from the weakref callback object remains: if the callback itself is
reachable, then the original object is reachable, and you don't have a
collectible cycle anymore.

    >>> c = C()
    >>> def cb2(obj):
    ...     print("weakref callback called with object reference")
    ...
    >>> weakref.finalize(c, cb2, c)
    <finalize object at 0x7f4300b710b0; for 'C' at 0x7f42f8ae3470>
    >>> del c
    >>>

Changing that to support resurrecting the object so it can be passed
into the callback without the callback itself holding a strong
reference means losing the main "reasoning about software" benefit
that weakref callbacks offer: they currently can't resurrect the
object they relate to (since they never receive a strong reference to
it), so it nominally doesn't matter if the interpreter calls them
before or after that object has been entirely cleaned up.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list