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

Guido van Rossum guido@python.org
Thu, 02 Mar 2000 17:45:37 -0500


> >>>>> "GvR" == Guido van Rossum <guido@python.org> writes:
> 
>     GvR> Now I have a choice to make.  If the class has an __init__,
>     GvR> should I clear the flag only after __init__ succeeds?  This
>     GvR> means that if __init__ raises an exception, __del__ is never
>     GvR> called.  This is an incompatibility.  It's possible that
>     GvR> someone has written code that relies on __del__ being called
>     GvR> even when __init__ fails halfway, and then their code would
>     GvR> break.

[Barry]
> It reminds me of the separation between object allocation and
> initialization in ObjC.  

Is that good or bad?

>     GvR> But it is just as likely that calling __del__ on a partially
>     GvR> uninitialized object is a bad mistake, and I am doing all
>     GvR> these cases a favor by not calling __del__ when __init__
>     GvR> failed!
> 
>     GvR> Any opinions?  If nobody speaks up, I'll make the change.
> 
> I think you should set the flag right before you call __init__(),
> i.e. after (nearly all) the C level initialization has occurred.
> Here's why: your "favor" can easily be accomplished by Python
> constructs in the __init__():
> 
> class MyBogo:
>     def __init__(self):
> 	self.get_delified = 0
> 	do_sumtin_exceptional()
> 	self.get_delified = 1
> 
>     def __del__(self):
> 	if self.get_delified:
> 	    ah_sweet_release()

But the other behavior (call __del__ even when __init__ fails) can
also easily be accomplished in Python:

    class C:

        def __init__(self):
            try:
                ...stuff that may fail...
            except:
                self.__del__()
                raise

        def __del__(self):
            ...cleanup...

I believe that in almost all cases the programmer would be happier if
__del__ wasn't called when their __init__ fails.  This makes it easier
to write a __del__ that can assume that all the object's fields have
been properly initialized.

In my code, typically when __init__ fails, this is a symptom of a
really bad bug (e.g. I just renamed one of __init__'s arguments and
forgot to fix all references), and I don't care much about cleanup
behavior.

--Guido van Rossum (home page: http://www.python.org/~guido/)