Search code examples
pythondestructor

Why isn't __del__ called twice?


I want to use an object's __del__ method to automatically write the object data to either an external database or a local cache (a global dict), depending on certain conditions. A context manager doesn't work for me.

However, this means that, once __del__ is called (because the object has gone out of scope), a new reference to the object may be created in the local cache. Because this sounded like potential trouble, I wrote a simple short test case:

cache = []

class Temp:
    def __init__(self) -> None:
        self.cache = True

    def __del__(self) -> None:
        print('Running del')
        if self.cache:
            cache.append(self)

def main():
    temp = Temp()
    print(temp.cache)

main()
if cache:
    print(cache[0].cache)

When I run this, it outputs:

True
Running del
True

Whereas I expected

True
Running del
True
Running del

I.e. __del__ called twice, once when it originally went out of scope at the end of main and once at the end of the program, since a new reference was stored in the cache. Why didn't __del__ run twice?


Solution

  • This is implementation specific behavior, see the docs of __del__. You are performing a "resurrection", i.e. you abort the garbage collection of an object. In older versions of python, this would have easily crashed your interpreter, but since PEP 442 this should mostly work. However, CPython specifically doesn't call the __del__ of a resurrected object on interpreter shutdown.

    In general, avoid accessing anything that isn't directly tied to your object in an __del__ method, including for example the global cache variable. There is no guarantee that it still exists.

    For this usecase, use context managers, or since these are apparently not usable for you, atexit.