Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why aren't destructors guaranteed to be called on interpreter exit?

From the python docs:

It is not guaranteed that __del__() methods are called for objects that still exist when the interpreter exits.

Why not? What problems would occur if this guarantee were made?

like image 394
Shea Levy Avatar asked Jan 31 '13 14:01

Shea Levy


People also ask

Are destructors called on exit in C++?

No, most destructors are not run on exit() . Essentially, when exit is called static objects are destroyed, atexit handlers are executed, open C streams are flushed and closed, and files created by tmpfile are removed.

Does C++ automatically call destructors?

In C++, we can manage resources by objects, i.e. acquiring resource in Ctor, and releasing it in Dtor (RAII). This relies on C++'s automatic destructor invocation.

Why destructor is used when delete is there?

When delete is used to deallocate memory for a C++ class object, the object's destructor is called before the object's memory is deallocated (if the object has a destructor). If the operand to the delete operator is a modifiable l-value, its value is undefined after the object is deleted.

Which of the following is false statement about destructor in python?

Right Answer is: B 2. False: It is executed whenever an object of its class goes out of scope or whenever the delete expression is applied to a pointer to the object of that class. It is called just before the object go out of scope or just before its life ends. 3.


2 Answers

I'm not convinced by the previous answers here.

Firstly note that the example given does not prevent __del__ methods being called during exit. In fact, the current CPythons will call the __del__ method given, twice in the case of Python 2.7 and once in the case of Python 3.4. So this can't be the "killer example" which shows why the guarantee is not made.

I think the statement in the docs is not motivated by a design principle that calling the destructors would be bad. Not least because it seems that in CPython 3.4 and up they are always called as you would expect and this caveat seems to be moot.

Instead I think the statement simply reflects the fact that the CPython implementation has sometimes not called all destructors on exit (presumably for ease of implementation reasons).

The situation seems to be that CPython 3.4 and 3.5 do always call all destructors on interpreter exit.

CPython 2.7 by contrast does not always do this. Certainly __del__ methods are usually not called on objects which have cyclic references, because those objects cannot be deleted if they have a __del__ method. The garbage collector won't collect them. While the objects do disappear when the interpreter exits (of course) they are not finalized and so their __del__ methods are never called. This is no longer true in Python 3.4 after the implementation of PEP 442.

However, it seems that Python 2.7 also does not finalize objects that have cyclic references, even if they have no destructors, if they only become unreachable during the interpreter exit.

Presumably this behaviour is sufficiently particular and difficult to explain that it is best expressed simply by a generic disclaimer - as the docs do.

Here's an example:

class Foo(object):
    def __init__(self):
        print("Foo init running")

    def __del__(self):
        print("Destructor Foo")

class Bar(object):
    def __init__(self):
        print("Bar1 init running")
        self.bar = self
        self.foo = Foo()

b = Bar()

# del b

With the del b commented out, the destructor in Foo is not called in Python 2.7 though it is in Python 3.4.

With the del b added, then the destructor is called (at interpreter exit) in both cases.

like image 129
strubbly Avatar answered Oct 06 '22 01:10

strubbly


If you did some nasty things, you could find yourself with an undeletable object which python would try to delete forever:

class Phoenix(object):
    def __del__(self):
        print "Deleting an Oops"
        global a
        a = self

a = Phoenix()

Relying on __del__ isn't great in any event as python doesn't guarantee when an object will be deleted (especially objects with cyclic references). That said, perhaps turning your class into a context manager is a better solution ... Then you can guarantee that cleanup code is called even in the case of an exception, etc...

like image 21
mgilson Avatar answered Oct 05 '22 23:10

mgilson