order that destructors get called?

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Thu Apr 8 07:03:19 CEST 2010

En Wed, 07 Apr 2010 19:08:14 -0300, Brendan Miller <catphive at catphive.net>  

> I'm used to C++ where destrcutors get called in reverse order of  
> construction
> like this:
> {
>     Foo foo;
>     Bar bar;
>     // calls Bar::~Bar()
>     // calls Foo::~Foo()
> }

That behavior is explicitly guaranteed by the C++ language. Python does  
not have such guarantees -- destructors may be delayed an arbitrary amount  
of time, or even not called at all.
In contrast, Python does have a `try/finally` construct, and the `with`  
statement. If Foo and Bar implement adequate __enter__ and __exit__  
methods, the above code would become:

with Foo() as foo:
   with Bar() as bar:
     # do something

On older Python versions it is more verbose:

foo = Foo()
   bar = Bar()
     # do something

> I'm writing a ctypes wrapper for some native code, and I need to manage  
> some
> memory. I'm wrapping the memory in a python class that deletes the  
> underlying
>  memory when the python class's reference count hits zero.

If the Python object lifetime is tied to certain lexical scope (like the  
foo,bar local variables in your C++ example) you may use `with` or  
`finally` as above.
If some other object with a longer lifetime keeps a reference, see below.

> When doing this, I noticed some odd behaviour. I had code like this:
> def delete_my_resource(res):
>     # deletes res
> class MyClass(object):
>     def __del__(self):
>         delete_my_resource(self.res)
> o = MyClass()
> What happens is that as the program shuts down, delete_my_resource is  
> released
> *before* o is released. So when __del__ get called, delete_my_resource  
> is now
> None.

Implementing __del__ is not always a good idea; among other things, the  
garbage collector cannot break a cycle if any involved object contains a  
__del__ method. [1]
If you still want to implement __del__, keep a reference to  
delete_my_resource in the method itself:

      def __del__(self,

(and do the same with any global name that delete_my_resource itself may  

The best approach is to store a weak reference to foo and bar somewhere;  
weak references are notified right before the referent is destroyed. [4]

And last, if you want to release something when the program terminates,  
you may use the atexit module.

> What I'm wondering is if there's any documented order that reference  
> counts
> get decremented when a module is released or when a program terminates.

Not much, as Stephen Hansen already told you; but see the comments in  
PyImport_Cleanup function in import.c [2] and in _PyModule_Clear in  
moduleobject.c [3]
Standard disclaimer: these undocumented details only apply to the current  
version of CPython, may change in future releases, and are not applicable  
at all to other implementations. So it's not a good idea to rely on this  

[1] http://docs.python.org/reference/datamodel.html#object.__del__
[2] http://svn.python.org/view/python/trunk/Python/import.c?view=markup
[4] http://docs.python.org/library/weakref.html

Gabriel Genellina

More information about the Python-list mailing list