[Python-Dev] Design question: call __del__ only after successful __init__?
Guido van Rossum
guido@python.org
Fri, 03 Mar 2000 12:05:00 -0500
OK, so we're down to this one point: if __del__ resurrects the object,
should __del__ be called again later? Additionally, should
resurrection be made illegal?
I can easily see how __del__ could *accidentally* resurrect the object
as part of its normal cleanup -- e.g. you make a call to some other
routine that helps with the cleanup, passing self as an argument, and
this other routine keeps a helpful cache of the last argument for some
reason. I don't see how we could forbid this type of resurrection.
(What are you going to do? You can't raise an exception from
instance_dealloc, since it is called from DECREF. You can't track
down the reference and replace it with a None easily.)
In this example, the helper routine will eventually delete the object
from its cache, at which point it is truly deleted. It would be
harmful, not helpful, if __del__ was called again at this point.
Now, it is true that the current docs for __del__ imply that
resurrection is possible. The intention of that note was to warn
__del__ writers that in the case of accidental resurrection __del__
might be called again. The intention certainly wasn't to allow or
encourage intentional resurrection.
Would there really be someone out there who uses *intentional*
resurrection? I severely doubt it. I've never heard of this.
[Jack just finds a snag]
> The __init__ rule for calling __del__ has me confused. Is this per-class or
> per-object?
>
> I.e. what will happen in the following case:
>
> class Purse:
> def __init__(self):
> self.balance = WithdrawCashFromBank(1000)
>
> def __del__(self):
> PutCashBackOnBank(self.balance)
> self.balance = 0
>
> class LossyPurse(Purse):
> def __init__(self):
> Purse.__init__(self)
> raise 'kaboo! kaboo!'
>
> If the new scheme means that the __del__ method of Purse isn't called I think
> I don't like it. In the current scheme I can always program defensively:
> def __del__(self):
> try:
> b = self.balance
> self.balance = 0
> except AttributeError:
> pass
> else:
> PutCashBackOnBank(b)
> but in a new scheme with a per-object "__del__ must be called" flag I can't...
Yes, that's a problem. But there are other ways for the subclass to
break the base class's invariant (e.g. it could override __del__
without calling the base class' __del__).
So I think it's a red herring. In Python 3000, typechecked classes
may declare invariants that are enforced by the inheritance mechanism;
then we may need to keep track which base class constructors succeeded
and only call corresponding destructors.
--Guido van Rossum (home page: http://www.python.org/~guido/)