Welcome to another tutorial, here you learn about Destructors in Python. In the previous tutorial, you learned about constructors as they are used to create and initialize an object, but, a destructor is used to destroy the object and perform the final clean-up.
However, we have a garbage collector in Python, to clean up the memory. Surprisingly, it is not only the memory that needs cleaning up, when an object is destroyed or dereferenced, there are other sources such as closing open files, cleaning the buffer or cache, closing database connections, and so on. Therefore, the word-final clean-up does not refer to cleaning up the memory resources only.
You already learned about how an object is created in one of the previous tutorials in this tutorial series, by using the '__new__' method and initializing using the ‘__init__’ method. In this tutorial, you will learn how to destroy the object.
Just as explained in the previous tutorial, the ‘__init__’ method is not necessarily the constructor method because it is just responsible to initialize the object variables and not creating the object, which is done by the __new__ method. However, the concept of destructors is also a little blur in python programmers, although commonly the_del__ method is considered the destructor method.
In the example below, we have the class Example, in which, we have used the __init__ method to initialize our object, after which have defined the __del__ method to act as a destructor.
class Example:
def __init__(self):
print ("Object created");
# destructor
def __del__(self):
print ("Object destroyed");
# creating an object
myObj = Example();
# to delete the object explicitly
del myObj;
Output:
Object created
Object destroyed
Just as discussed in the above sections, using __del__ is not a full-proof solution to perform the final clean-up for an object which is no longer required.
Below are two situations where the __del__ function behaves absurdly.
This type of referencing refers to a situation in which two objects refer to one another. in this case, both of these objects go out of reference, and at this point, is confused to destroy which object first, and to avoid any error, it does not destroy any of the objects.
Check out this example:
class Foo():
def __init__(self, id, bar):
self.id = id;
# saving reference of Bar object
self.friend = bar;
print ('Foo', self.id, 'born');
def __del__(self):
(print 'Foo', self.id, 'died');
class Bar():
def __init__(self, id):
self.id = id;
# saving Foo class object in variable
# 'friend' of Bar class, and sending
# reference of Bar object for Foo object
# initialisation
self.friend = Foo(id, self);
print ('Bar', self.id, 'born')
def __del__(self):
print ('Bar', self.id, 'died')
b = Bar(12)
Output:
Foo 12 born
Bar 12 born
In OOP, a destructor can only be called in situations where an object is successfully created. This is so, because, if any exception occurs in the constructor then the constructor itself destroys the object.
However, in python, if any exception occurs in the method __init__while initializing the object, the method __del__ gets called.
However, whether the object was never initialized correctly, the method __del__ will try to empty all the resources and variables and in turn, may lead to another exception.
class Example():
def __init__(self, x):
# for x = 0, raise exception
if x == 0:
raise Exception();
self.x = x;
def __del__(self):
print (self.x)
# creating an object
myObj = Example();
# to delete the object explicitly
del myObj
Output:
Exception exceptions.AttributeError: "'Example' object has no attribute 'x'" in <bound
method Example.__del__ of <__main__.Example object at 0x02449570>> ignored