Learning Object-Oriented Programming
上QQ阅读APP看书,第一时间看更新

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.