Skip to content

June 30, 2015

Python 3: __del__ method and imported modules

by Joe Kuan

My python script generates the following error and the strange thing is that this error only occurs occasionally:

Exception AttributeError: "'NoneType' object has no attribute 'path'" in 
<bound method Client.__del__ of <__main__.MyObject object at 0x108c3dc50>> ignored

Basically, it complaints that the __del__ (destructor) of the MyObject class is trying to call a method from a NoneType object. Here is the sample of the code:

#!/usr/local/bin/python3

import os.path, tempfile, os, sys

class MyObject(object):

    def __init__(self):
        tempFile = tempfile.gettempdir() + '/fixname.txt'
        f = open(tempFile, 'w')
        f.write('Some data')
        f.close()
        self.tempFile = f.name
        print (self.tempFile)
        
    def __del__(self):
        if os.path.exists(self.tempFile):
            os.remove(self.tempFile)

if __name__ == "__main__":
    myObj = MyObject()

The reason for that is the new behavior of the __del__ method in python 3. Here is the description from the python reference manual

Warning Due to the precarious circumstances under which __del__() methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed to sys.stderr instead. Also, when __del__() is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the __del__() method may already have been deleted or in the process of being torn down (e.g. the import machinery shutting down). For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants. Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called.

So by the time the __del__ method is called, any global reference MAY not be available anymore. If you really need to use module’s methods inside a __del__ method, perhaps you have to re-import the module

    def __del__(self):
        import os.path
        if os.path.exists(self.tempFile):
            os.remove(self.tempFile)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: