Yup, I think Carsten got it. Mystery solved!

You could replace Person with self.__class__ instead of type(self) if Person is an old-style class (since the class won't be collected until after all the instances are collected (because each instance references it's class)). Note that when the name "Person" is set to None, the Person class has it's reference count reduced by one but it is not yet collected.

Alternatively, if you name your locals to start with "_" (e.g. _cathy) you avoid this problem /"Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called."/

But in general, I have this to say: IMO __del__ should not be taught to beginners (other than to say "don't use __del__ yet; you have much to learn first young jedi"). It should always be put in the "advanced topics" section when included in beginning python books along with threads, process control, and extending/embedding. If you think you need it, you probably don't.

It is an advanced concept that requires a basic understanding of garbage collection. Beginners shouldn't really have to know much about garbage collection. The whole point is that it is automatic.

__del__ is particularly dangerous for experienced C++ programmers starting to learn Python. People look for analogies and when they see __del__ they think "destructor" which is sort of vaguely right, but completely wrong in practice. The practical difference is that in C++ you actually have to deal with implementing destructors all of the time, and you can't get very far as a C++ programmer without using them, whereas in python you almost never have to deal with destructors. In C++, destructors are usually predictable (in correct code), but in python code they are somewhat harder to predict because they are invoked implicitly at the whim of the python implementation.

In practice you don't need to use __del__ unless you are doing something exotic like explicitly implementing your own memory model, or tuning resource allocation in a large system. If you are doing ordinary day-to-day programming don't even think about __del__.

Ken Seehart


Carsten Haese wrote:
On Sun, 2008-03-23 at 17:42 -0700, George Sakkis wrote:
That's really weird... it's reproducible on Windows too. It doesn't
make any sense why the name of the variable would make a difference.
My guess is you hit some kind of obscure bug.

This is not a bug, just an unexpected feature:
http://mail.python.org/pipermail/python-list/2005-January/304873.html

What's happening is that at the end of the script, all objects in the
global namespace are set to None (in order to decrease their reference
count and trigger garbage collection). This happens in the order in
which the names appear as keys in the globals dictionary. It randomly
happens that "swaroop", "kalam", and "cath" all are hashed in front of
"Person", but "cathy" is hashed after "Person".

Hence, if Catherine is named cath, Python "None's" all the instances
first and then the type last, and all is well. However, if Catherine is
called cathy, Person is set to None before cathy. Then, in the lookup of
the global name "Person" during cathy.__del__, Person is None, which
doesn't have a "population" attribute, causing the AttributeError.

Possible workarounds are:
1) Explicitly delete the global names for the instances before the
script runs out.
2) Don't refer to the "Person" type by its global name in __del__, but
indirectly as type(self). (This requires Person to be a new-style class,
though.)


-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to