python - Python destructor and explicitly cleanup

Normally we will use __init__ as the constructor, but what shall we do when we are done with the object?
the key lies in the __del__ method, when the object's reference counting is down to 0, then the destructor will be called. 
Below shows an example object that wraps around the file object.

class SpecialFiles(object):
    '''
    classdocs
    '''


    def __init__(self, file_name):
        '''
        Constructor
        '''
        self.__file = open(file_name, 'w')
        self.__file.write("**** Start Special File **** \n\n")
    def write(self, str):
        self.__file.write(str)
    def writelines(self, str_list):
        self.__file.writelines(str_list)
    def __del__(self):
        if self.__file is not None:
            print("__del__ called on", self.__file.name)
            self.__file.close()
        else:
            print("close() is already called")
    def close(self):
        if self.__file:
            self.__file.write('\n\n**** End Special File')
            self.__file.close()
            self.__file = None

First we have defined a __del__ method which shall be called when the reference counting is reaching 0, and we are also providing a close() method which we can deterministic destruct an object, and internally it shall call the __del__ ethod. Below shows how we will use it . 

import unittest
from Classes.Inheritances.Destructors import SpecialFiles


class Test(unittest.TestCase):


    def testDestructors(self):
        f = SpecialFiles('testfile')
        f.write('11111\n')
        f.close() 
    def testDestructors1(self):
        f = SpecialFiles('testfile')
so when you run this test method, you will see when the references are reaching the 0, the __del__ method will be called automatically, but in the testDestructors, we can see the cleanup mehtod close runs before the function returns, but the __del__ method runs after the function is returned.
But shall we relies on the automatic resource reclaimation? It is all possible except when there is circular references.Let's see the example.
class Circle:            
    def __init__(self, name, parent):
        self.name = name
        self.parent = parent
        self.child = None
        if parent:
            parent.child = self
    def cleanup(self):
        self.child = self.parent = None
    def __del__(self):
        print("__del__ called on", self.name)
Let's make two test cases, one is a test case with circular reference, one is a test case without.
import unittest
from Classes.Inheritances.Destructors import Circle


class Test(unittest.TestCase):


    def testMemoryLeakage(self):
        # you won't see
        #  __del__ called on
        a = Circle("a", None)
        b = Circle("b", a)
        
    def testToBreakCircularReferences(self):
        c = Circle('c', None)
        d = Circle('d', c)
        d.cleanup()
        


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testDestructors']
    unittest.main()
As you can see, when you are in doubt, you shall always provide a explicit cleanup method, like the cleanup method which showed above, which can help to break the circular reference and more importantly explicitly clean up the resource if necessary.


你可能感兴趣的:(python)