python's newbie question

Duncan Booth duncan.booth at invalid.invalid
Thu Oct 12 05:52:01 EDT 2006


tpochep at mail.ru wrote:

> I tried different names instead of b1, sometimes programm works,
> sometimes I have an exception. So it's clear, that I've done some
> stupid mistake, but it's not clear for me, python's newbie, where :)

Not a stupid mistake, although as you come to use Python more you will 
learn that you need __del__ methods very rarely if at all. This is just as 
well as writing reliable __del__ methods can be non-trivial.

The problem you have is that your __del__ method is being called as Python 
tidies up before exiting. It does this by going systematically through all 
the modules and deleting all of their global variables. If you are using 
__del__ you have to be aware that by the time it gets called not all global 
variables still exist.

The order in which the globals are deleted isn't defined, in this case it 
looks like Base1 has been deleted before Derived, but that won't always be 
the case.

One option is to use new-style classes and use super() to pass the call up 
to the base classes (super is a builtin, and builtins should still be 
around when your code is being cleaned up). Another option would be to 
access the base classes through Derived.__bases__.

Probably the best solution is to remove any objects which required cleanup 
from your class hierarchy. e..g if Derived has a __del__ method because it 
needs to close a database, have a separate object representing the database 
which does its own cleanup. Then Derived doesn't need to call 
self.database.close() because that will happen automatically when 
self.database is destroyed, so Derived won't need a __del__.

Here's your code pushing the __del__ method out of the class hierarchy. But 
watch out: if you pass self as an argument to printer then nothing gets 
destroyed at all as the program exits, and of course the order in which the 
__del__ prints appear is now undefined.

class printer(object):
    def __init__(self, *args):
        self.msg = args
    def __del__(self):
        print ' '.join(self.msg)

class Base1:
    def __init__(self):
        print "Base1.__init__", self
        self.__del = printer("Base1.__del__")

class Base2:
    def __init__(self):
        print "Base2.__init__", self
        self.__del = printer("Base2.__del__")

class Derived(Base1, Base2):
    def __init__(self):
        print "Derived.__init__:"
        Base1.__init__(self)
        Base2.__init__(self)
        self.__del = printer("Derived.__del__:")

print "begin..."
d = Derived()
b = d
print "end..."



More information about the Python-list mailing list