Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Exception error when accessing the class variable at the termination of the program

4 views
Skip to first unread message

jwa...@vsnl.net

unread,
Feb 2, 2009, 2:52:51 AM2/2/09
to pytho...@python.org
Hi All,

Here is a sample piece of code with which I am having a problem, with Python version 2.4.4

class Person:
Count = 0 # This represents the count of objects of this class

def __init__(self, name):
self.name = name
print name, ' is now created'
Person.Count += 1

def __del__(self):
print self.name, ' is now deleted'
Person.Count -= 1
if Person.Count == 0:
print 'The last object of Person class is now deleted'
else:
print 'There are still', Person.Count, ' objects of class Person'

x2 = Person("Krishna")
del x2

When the above code is executed, it works properly.

If the last statement del x2, is removed, then when the program terminates, this throws up an exception as shown below

Krishna is now created
Krishna is now deleted
Exception exceptions.AttributeError: "'NoneType' object has no attribute 'Count'
" in <bound method Person.__del__ of <__main__.Person instance at 0xf6532f6c>> ignored

Can someone please explain why the exception happens in the case where there is no explicit del statement?

Thanks
Jana

Chris Rebert

unread,
Feb 2, 2009, 4:37:08 AM2/2/09
to jwa...@vsnl.net, pytho...@python.org

Without the `del`, the reference count of x2 remains >0 and so is not
deleted until the program ends. This affects when __del__ is executed,
which matters greatly.

>From the section on __del__ on
http://www.python.org/doc/2.3.5/ref/customization.html :
Warning: Due to the precarious circumstances under which __del__()
methods are invoked, exceptions that occur during their execution are
ignored, and a warning is printed to sys.stderr instead. Also, when
__del__() is invoked in response to a module being deleted (e.g., when
execution of the program is done), ***other globals referenced by the
__del__() method may already have been deleted***. For this reason,
__del__() methods should do the absolute minimum needed to maintain
external invariants. [etc., emphasis mine]

Since without the `del`, __del__ is only called at the end of the
program, Person and/or Count may have already been GC-ed by the time
__del__ is called (the order objects are GC-ed in is a bit
unpredictable), hence the error you get which is saying, in a slightly
obtuse way, that Person has been GC-ed already.
As the Warning states, __del__ shouldn't be relied upon to do fancy
stuff like you're having it do. You would be better off using an
explicit finalizer method in this case, like .close() for file
objects.

For example:

try:


x2 = Person("Krishna")

#do stuff with x2
finally:
x2.delete() #causes count to be decremented

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com

Duncan Booth

unread,
Feb 2, 2009, 4:37:21 AM2/2/09
to
jwa...@vsnl.net wrote:

> Can someone please explain why the exception happens in the case
> where there is no explicit del statement?

When Python is ecleaning up as it exits, it clears all the global
variables in each module by setting them to None. This happens in an
arbitrary and unpredictable order: in this particular case it set Person
to None before setting x2 to None.

If you must have a __del__ method on a class then you should take care
not to access any globals from inside the __del__ method (or any
function it calls). Alternatively you could just catch and ignore any
exceptions thrown from your __del__ method.

In the example you gave, provided you never subclass Person you could
use self.__class__.Count to access your class variable. However in many
cases you'll probably find that a much better solution is to use weak
references. e.g. a WeakValueDictionary mapping id(self) to self:

from weakref import WeakValueDictionary

class Person:
_instances = WeakValueDictionary()

def __init__(self, name):
self.name = name

self._instances[id(self)] = self


print name, 'is now created'

@property
def Count(self):
return len(self._instances)

def __del__(self):
print self.name, 'is now deleted'

if self.Count==0:


print 'The last object of Person class is now deleted'
else:

print 'There are still', self.Count, 'objects of class
Person'

x2 = Person('Krishna')

# del x2


--
Duncan Booth http://kupuguy.blogspot.com

0 new messages