[Python-Dev] Design question: call __del__ only after successful __init__?

Tim Peters tim_one@email.msn.com
Fri, 3 Mar 2000 00:38:59 -0500


[Guido]
> I was looking at the code that invokes __del__, with the intent to
> implement a feature from Java: in Java, a finalizer is only called
> once per object, even if calling it makes the object live longer.

Why?  That is, in what way is this an improvement over current behavior?

Note that Java is a bit subtle:  a finalizer is only called once by magic;
explicit calls "don't count".

The Java rules add up to quite a confusing mish-mash.  Python's rules are
*currently* clearer.

I deal with possible exceptions in Python constructors the same way I do in
C++ and Java:  if there's a destructor, don't put anything in __init__ that
may raise an uncaught exception.  Anything dangerous is moved into a
separate .reset() (or .clear() or ...) method.  This works well in practice.

> To implement this, we need a flag in each instance that means "__del__
> was called".

At least <wink>.

> I opened the creation code for instances, looking for the right place
> to set the flag.  I then realized that it might be smart, now that we
> have this flag anyway, to set it to "true" during initialization.  There
> are a number of exits from the initialization where the object is created
> but not fully initialized, where the new object is DECREF'ed and NULL is
> returned.  When such an exit is taken, __del__ is called on an
> incompletely initialized object!

I agree *that* isn't good.  Taken on its own, though, it argues for adding
an "instance construction completed" flag that __del__ later checks, as if
its body were:

    if self.__instance_construction_completed:
        body

That is, the problem you've identified here could be addressed directly.

> Now I have a choice to make.  If the class has an __init__, should I
> clear the flag only after __init__ succeeds?  This means that if
> __init__ raises an exception, __del__ is never called.  This is an
> incompatibility.  It's possible that someone has written code that
> relies on __del__ being called even when __init__ fails halfway, and
> then their code would break.
>
> But it is just as likely that calling __del__ on a partially
> uninitialized object is a bad mistake, and I am doing all these cases
> a favor by not calling __del__ when __init__ failed!
>
> Any opinions?  If nobody speaks up, I'll make the change.

I'd be in favor of fixing the actual problem; I don't understand the point
to the rest of it, especially as it has the potential to break existing code
and I don't see a compensating advantage (surely not compatibility w/
JPython -- JPython doesn't invoke __del__ methods at all by magic, right?
or is that changing, and that's what's driving this?).

too-much-magic-is-dizzying-ly y'rs  - tim