Bug in __del__ function

From: David MacQuigg (dmq_at_gain.com)
Date: 06/24/04

Date: Wed, 23 Jun 2004 18:07:50 -0700

I'm __del__() to decrement a count of instances of a class whenever an
instance is deleted, and I'm getting very erratic behavior. This is
in CPython, which I am told has no problem with reference counts
getting out-of-sync with the deletion of instances. The behavior of
__del__() seems to be very sensitive to the exact sequence of

The example below is a repeatable test case. It might be possible to
simplify this further, but at this point, I haven't a clue as to why
it works with some sequences of commands, but not others.

I'm also not able to repeat the problem by putting the commands in the
file, and just running the file. Adding the necessary 'print'
keywords makes the problem go away. This could be just a problem in
IDLE, but unless I'm sure of that, I don't want to be using __del__ in
my programs.

Is this a bug, or have I misunderstood the use of __del__?

-- Dave

### test__del__.py

class Animal(object):
    _count = 0
    def __init__(self):
        print "Creating instance:", self
        self.__class__._count += 1
    def __del__(self):
        print "Deleting instance:", self
        self.__class__._count -= 1
        print countem()

class Mammal(Animal):
    _count = 0

class Cat(Mammal):
    _count = 0

def countem():
    str = ''
    for cls in Cat.__mro__[:-1]:
        str += '%9s:%s' % (cls.__name__, cls._count)
    return str

import sys
def rc(obj):
    print "sys.getrefcount(obj):", sys.getrefcount(obj)

### Run the above file in IDLE:

Python 2.3.4 (#53, May 25 2004, 21:17:02) [MSC v.1200 32 bit (Intel)]
on win32
IDLE 1.0.3
>>> ================================ RESTART ===================
>>> cat1 = Cat()
Creating instance: <__main__.Cat object at 0x00A11F70>
>>> cat2 = cat1
>>> countem()
' Cat:1 Mammal:0 Animal:0'
>>> rc(cat1)
sys.getrefcount(obj): 5
>>> rc(cat2)
sys.getrefcount(obj): 5
>>> del cat1
>>> cat2
<__main__.Cat object at 0x00A11F70>
>>> rc(cat2)
sys.getrefcount(obj): 5 ### Should be one less.
>>> del cat2 ### Should delete instance.
>>> countem()
Deleting instance: <__main__.Cat object at 0x00A11F70>
      Cat:0 Mammal:0 Animal:0
' Cat:1 Mammal:0 Animal:0' ### Count is wrong.
>>> countem()
' Cat:0 Mammal:0 Animal:0' ### Count is right.

### END ###