Customizing destructors in Python
We want to know when the instances of the Rectangle
class are removed from memory, that is, when the objects become inaccessible and get deleted by the garbage-collection mechanism. However, it is very important to notice that the ways in which garbage collection works depends on the implementation of Python. Remember that, Python runs on a wide variety of platforms.
Before Python removes an instance from memory, it calls the __del__
method. Thus, we can use this method to add any code we want to run before the instance is destroyed. We can think of the __del__
method as the equivalent of a destructor in other object-oriented programming languages.
The following lines declare a __del__
method within the body of the Rectangle
class. Remember that Python always receives self
as the first argument for any instance method:
def __del__(self): print('A Rectangle instance is being destroyed.')
The following lines create two instances of the Rectangle
class: rectangleToDelete1
and rectangleToDelete2
. Then, the next lines assign None
to both variables. Therefore, the reference count for both objects reaches 0
, and the garbage-collection mechanism deletes them. The Python console will display I'm initializing a new Rectangle instance.
and then A Rectangle instance is being destroyed.
twice in the Python console. Python executes the code within the __del__
method after we assign None
to each variable that had the only reference to an instance of the Rectangle
class:
rectangleToDestroy1 = Rectangle(293, 117) rectangleToDestroy2 = Rectangle(293, 137) rectangleToDestroy1 = None rectangleToDestroy2 = None
Tip
You can add some cleanup code within the __del__
method. However, take into account that most of the time, you can follow best practices to release resources without having to add code to the __del__
method. Remember that you don't know exactly when the __del__
method is going to be executed. Even when the reference count reaches 0
, the Python implementation might keep the resources until the appropriate garbage collection destroys the instances.
The following lines create a rectangle3
instance of the Rectangle
class and then assign a referenceToRectangle3
reference to this object. Thus, the reference count to the object increases to 2
. The next line assigns None
to rectangle3
, and therefore, the reference count for the object goes down from 2
to 1
. As the referenceToRectangle3
variable stills holds a reference to the Rectangle
instance, Python doesn't destroy the instance, and we don't see the results of the execution of the __del__
method:
rectangle3 = Rectangle(364, 257) referenceToRectangle3 = rectangle3 rectangle3 = None
Python destroys the instance if we add a line that assigns None
to referenceToRectangle3
:
referenceToRectangle3 = None
However, it is very important to know that you don't need to assign None
to a reference to force Python to destroy objects. In the previous examples, we wanted to understand how the __del__
method worked. Python will automatically destroy the objects when they aren't referenced anymore.