Mailing List Archive

strange behaviour at termination time
Basically there is a base class name that I found bound to None,
which prevents me to call base methods.

I tested it with 1.5.1 on Linux and 1.5.2 on Windows. Was working
fine with 1.4 in Debian/Linux 1.3.1 till I upgraded to Debian 2.1...

Bug or feature ? Quite annoying if feature...

More that it, I discovered during testing that sometimes it is correct
if I change the base class name !

Here is sample code to show it:

----------------------------------
class A :
def __del__ (self) :
print "A.__del__", self

class B (A) :
def __del__ (self) :
print "B.__del__", self, A
# can't do A.__del__ (self) for example

x = A ()
y = B ()
----------------------------------

In this configuration it should show ok.
If you change the name of the first class from A to X everywhere
then X is bound to None in B.__del__ !!!

Please can anyone explain me ?!
strange behaviour at termination time [ In reply to ]
Fabien COUTANT <fabien.coutant@steria.fr> wrote:
> Basically there is a base class name that I found bound to None,
> which prevents me to call base methods.
>
> I tested it with 1.5.1 on Linux and 1.5.2 on Windows. Was working
> fine with 1.4 in Debian/Linux 1.3.1 till I upgraded to Debian 2.1...
>
> Bug or feature ? Quite annoying if feature...

feature.

1.5.2 does a more aggressive global clean-up when the
interpreter is shut down. this includes zapping modules
and module globals, and replacing them with references
to None.

> More that it, I discovered during testing that sometimes it is correct
> if I change the base class name !

namespaces are dictionaries. changing the name may or may
not change the clean-up order...

> Here is sample code to show it:
>
> ----------------------------------
> class A :
> def __del__ (self) :
> print "A.__del__", self
>
> class B (A) :
> def __del__ (self) :
> print "B.__del__", self, A
> # can't do A.__del__ (self) for example
>
> x = A ()
> y = B ()
> ----------------------------------
>
> In this configuration it should show ok.
> If you change the name of the first class from A to X everywhere
> then X is bound to None in B.__del__ !!!

the only reasonable way to get around this is to explicitly
bind all the names you want in your destructor:

> def __del__ (self, A=A) :
> print "B.__del__", self, A
> A.__del__(self)

(btw, 1.4 probably didn't call B's destructor at all...)

</F>
strange behaviour at termination time [ In reply to ]
Fabien COUTANT <fabien.coutant@steria.fr> wrote:
> Basically there is a base class name that I found bound to None,
> which prevents me to call base methods.

also see:
http://www.python.org/doc/essays/cleanup.html
(this *was* implemented in 1.5.1)

</F>
strange behaviour at termination time [ In reply to ]
Fabien COUTANT wrote:
>
> If you change the name of the first class from A to X everywhere
> then X is bound to None in B.__del__ !!!

When the Python interpreter is shutting down, it
goes through all the loaded modules and sets all
the names defined in them to None. It does this in
an arbitrary order, and it appears that in this
case it happens to delete the name "A" after
"y", but "X" before "y".

To avoid problems like this, you have to design
your __del__ methods so that they can do their
work without having to refer to any module-level
names at the time they are called. One way is
to use the default-argument trick:

class B (A) :
def __del__ (self, A = A) :
A.__del__ (self)

Greg
strange behaviour at termination time [ In reply to ]
Greg Ewing wrote:

> To avoid problems like this, you have to design
> your __del__ methods so that they can do their
> work without having to refer to any module-level
> names at the time they are called. One way is
> to use the default-argument trick:
>
> class B (A) :
> def __del__ (self, A = A) :
> A.__del__ (self)

Can you explain why this trick works? When are the default arguments
stored in the method instance? I guess this happens when the method
instance for __del__ is created by the interpreter, right?

Thanks,
--
Ovidiu Predescu <ovidiu@cup.hp.com>
http://www.geocities.com/SiliconValley/Monitor/7464/
strange behaviour at termination time [ In reply to ]
From: Ovidiu Predescu <ovidiu@cup.hp.com>

Greg Ewing wrote:

> To avoid problems like this, you have to design
> your __del__ methods so that they can do their
> work without having to refer to any module-level
> names at the time they are called. One way is
> to use the default-argument trick:
>
> class B (A) :
> def __del__ (self, A = A) :
> A.__del__ (self)

Can you explain why this trick works? When are the default arguments
stored in the method instance? I guess this happens when the method
instance for __del__ is created by the interpreter, right?

Thanks,
--
Ovidiu Predescu <ovidiu@cup.hp.com>
http://www.geocities.com/SiliconValley/Monitor/7464/
strange behaviour at termination time [ In reply to ]
Ovidiu Predescu <ovidiu@cup.hp.com> writes:

> Greg Ewing wrote:
>
> > To avoid problems like this, you have to design
> > your __del__ methods so that they can do their
> > work without having to refer to any module-level
> > names at the time they are called. One way is
> > to use the default-argument trick:
> >
> > class B (A) :
> > def __del__ (self, A = A) :
> > A.__del__ (self)
>
> Can you explain why this trick works? When are the default arguments
> stored in the method instance? I guess this happens when the method
> instance for __del__ is created by the interpreter, right?

Yup, that's it. If you want to find out about these things, read the
language reference or import rlcompleter and bash the completion key a
lot. I this case you'll find

B.__del__.im_func.func_defaults

which will contain something like

<class A at xxxx in xxx>

HTH
Michael

> Thanks,
> --
> Ovidiu Predescu <ovidiu@cup.hp.com>
> http://www.geocities.com/SiliconValley/Monitor/7464/
strange behaviour at termination time [ In reply to ]
From: Michael Hudson <mwh21@cam.ac.uk>

Ovidiu Predescu <ovidiu@cup.hp.com> writes:

> Greg Ewing wrote:
>
> > To avoid problems like this, you have to design
> > your __del__ methods so that they can do their
> > work without having to refer to any module-level
> > names at the time they are called. One way is
> > to use the default-argument trick:
> >
> > class B (A) :
> > def __del__ (self, A = A) :
> > A.__del__ (self)
>
> Can you explain why this trick works? When are the default arguments
> stored in the method instance? I guess this happens when the method
> instance for __del__ is created by the interpreter, right?

Yup, that's it. If you want to find out about these things, read the
language reference or import rlcompleter and bash the completion key a
lot. I this case you'll find

B.__del__.im_func.func_defaults

which will contain something like

<class A at xxxx in xxx>

HTH
Michael

> Thanks,
> --
> Ovidiu Predescu <ovidiu@cup.hp.com>
> http://www.geocities.com/SiliconValley/Monitor/7464/