[Python-3000] Removing __del__

Tim Peters tim.peters at gmail.com
Tue Sep 26 13:01:23 CEST 2006


[Giovanni Bajo]
> Raymond, there is one thing I don't understand in your line of reasoning. You
> say that you prefer explicit finalization, but that implicit finalization still
> needs to be supported. And for that, you'd rather drop __del__ and use
> weakrefs. But why? You say that __del__ is harardous, but I can't see how
> weakrefs are less hazardous. As an implicit finalization method, they live on
> the fragile assumption that the callback won't hold a reference to the object:
> an assumption which cannot be enforced in any way but cautious programming and
> scrupolous auditing of the code.

Nope, not so.  Read Modules/gc_weakref.txt for the gory details.  In
outline, there are three objects of interest here:  the weakly
referenced object (WO), the weakref (WR) to the WO, and the callback
(CB) callable attached to the WR.

/Normally/ the CB is reachable (== not trash).  If a reachable CB has
a strong reference to the WO, then that keeps the WO reachable too,
and of course the CB won't be invoked so long as its strong reference
keeps the WO alive.  The CB can't become trash either so long as the
WR is reachable, since the WR holds a strong reference to the CB.  If
the WR becomes trash while the WO is reachable, the WR clears its
reference to the CB, and then the CB will never be invoked period.

OTOH, if the CB has a weak reference to the WO, then when the WO goes
away and the CB is invoked, the CB's weak reference returns None
instead of the WO.

So in no case can a reachable CB actually get at the WO via the CB's
own strong or weak reference to the WO.  More, this is true even if
the WO is just strongly reachable via any path /from/ a reachable CB:
the fact that the CB is reachable guarantees the WO is reachable then
too.

Skipping details, things get muddier only when all three of these
objects end up in cyclic trash (CT) "at the same time".  The dodge
Python currently takes is that, when a WR is part of CT, and the WR's
referent is also part of CT, the WR's CB (if any) is never invoked.
This is defensible since the order in which trash objects are
finalized isn't defined, so it's legitimate to kill the WR first.
It's unclear whether that's entirely desirable behavior, though.
There were excruciating discussions about this earlier, but nobody had
a concrete use case favoring a specific position.


More information about the Python-3000 mailing list