[Python-3000] Removing __del__

Giovanni Bajo rasky at develer.com
Thu Sep 21 00:39:48 CEST 2006

Michael Chermside <mcherm at mcherm.com> wrote:

>    from deletions import on_del_invoke
>    class Wrapper:
>        def __init__(self, *args):
>            self.handle = CAPI.init(*args)
>            on_del_invoke(self, CAPI.close, self.handle)
>        def foo(self):
>            CAPI.foo(self.handle)
> It's actually *fewer* lines this way, and I find it quite
> readable.

It's fewer lines, but *less* readable than a simple plain method call. It's
still an indirection.

> Furthermore, unlike the __del__ version it doesn't
> break as soon as someone accidentally puts a Wrapper object
> into a loop.

Yes, but I'm an adult and I know that it won't. I'm not even touching __del__
with a hundred foot pole if it's a class which has 1% of possibility of getting
into a loop, really. I know it will always be a "leaf" class, if you know what
I mean.

> Working from this example, I'm not convinced that the price
> of giving up __del__ is really all that high.

If you ask me, I don't think I can find any library solution to finalization
acceptable. Finalization is really something that ought to be easy. If the
cyclic GC and __del__ doesn't get along well together, let's substitute __del__
with another finalization feature in the core, with an easy syntax and
semantic, which can cope better with the cyclic GC. Again, I vote for the
__close__ method (which is: just fix the semantic).

> (But please,
> find another example to convince me!)

Let's say:

class Wrapper:
    def __init__(self, *args):
        self.handle = CAPI.init(*args)

    def close(self):
        if self.handle is not None:
            self.handle = None
    __del__ = close

Now what, remove_on_del_invokation()?

> On the other side of the scales, here are some benefits that
> we gain if we get rid of __del__:
>    * Simpler GC code which is less likely to have obscure
>      bugs that are incredibly difficult to track down. Less
>      core developer time spent maintaining complex, fragile
>      code.

This is an argument against the current semantic of __del__, not against any
finalization method which is invoked during the cyclic GC. I believe that
__close__ fixes these problems as well.

>    * No need to explain about keeping __del__ objects[1] out
>      of reference loops. In exchange, we choose explain
>      about not passing the object being monitored or
>      anything that links to it as arguments to on_del_invoke.
>      I find that preferable because: [...]

I think you are right in that the latter is preferable, but I think it's even
easier to just "avoid __del__ when coding, unless you are dramatically sure of
what you're doing". This way, you don't have to keep mental reference counts.

In fact, I believe we're missing a valuable tool for Python 2. Wouldn't be
possible to have a debug mode where, between each statement (or very often at
least), Python looks for cycles with __del__ in them, and abort execution? It
would be very useful to early detect uncollectable cycles at the moment they
are created, instead of doing long sessions trying to parse gc.garbage.

Giovanni Bajo

More information about the Python-3000 mailing list