On 21 October 2016 at 17:09, Nathaniel Smith njs@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.