__del__

Updated March 26, 2026 · Dunder Methods
python __del__ dunder-methods garbage-collection

Short Description

__del__ is a special method Python calls when an object is about to be garbage collected. It is commonly referred to as a destructor, though it is not a true destructor in the C++ sense. Python makes no guarantees about when (or if) __del__ will be called, and it should almost never be used in modern Python 3 code.

Syntax

class MyClass:
    def __del__(self):
        # cleanup code here
        pass

__del__ takes exactly one parameter — self. Returning a value from __del__ is legal but meaningless and should be avoided.

Relationship to Garbage Collection

In CPython (the standard implementation), objects are destroyed immediately when their reference count reaches zero. In this case, __del__ runs synchronously at destruction time. However, this behavior is an implementation detail of CPython, not a language guarantee.

Python’s garbage collector (gc module) handles reference cycles — groups of objects that reference each other with no external references. If a cycle contains an object with a __del__ method, that cycle cannot be collected automatically. Python moves such cycles to gc.garbage instead, where they persist until manually cleaned up.

import gc

class Node:
    def __init__(self, next_node=None):
        self.next = next_node

    def __del__(self):
        print("Node deleted")

a = Node()
b = Node(a)
a.next = b  # a -> b -> a cycle

a = None
b = None
gc.collect()  # Moves cycle to gc.garbage — __del__ NOT called
# output: (nothing — cycle with __del__ cannot be auto-collected)

Calling gc.collect() does not guarantee __del__ will run for objects in cycles.

__del__ vs try/finally

Property__del__try/finally
When it runsNon-deterministic — at GC timeDeterministic — immediately on block exit
Interpreter shutdownNot calledCalled
ExceptionsPrinted to stderr, not raisedPropagated normally
Reference cyclesCannot collect cycles with __del__N/A

For resource cleanup, try/finally (or a context manager via with) is always preferred. It guarantees execution on every code path out of a block.

class DatabaseConnection:
    def close(self):
        print("Connection closed")

# Preferred: context manager guarantees cleanup
conn = DatabaseConnection()
try:
    print("Using connection")
finally:
    conn.close()
# output: Using connection
# output: Connection closed

Common Pitfalls

Exceptions are swallowed

If __del__ raises an exception, Python prints a traceback to stderr and continues. The exception does not propagate.

class Bad:
    def __del__(self):
        raise ValueError("error in __del__")

b = Bad()
del b
# output: Exception ignored in __del__...
#        Traceback (most recent call last):
#        ...
#        ValueError: error in __del__

Circular references with __del__ are never collected

Any object with a __del__ that participates in a reference cycle cannot be garbage collected automatically. The cycle is moved to gc.garbage and __del__ is never called.

Not called on interpreter shutdown

If Python exits via sys.exit() or a fatal error, __del__ is not called for remaining objects. Global variables set to None during shutdown can also cause unpredictable behavior.

Parent __del__ not called automatically

When a subclass defines __del__, Python calls only the subclass’s version. You must call the parent’s __del__ manually via super().

class Parent:
    def __del__(self):
        print("Parent cleanup")

class Child(Parent):
    def __del__(self):
        print("Child cleanup")
        super().__del__()  # Required — Python does not call it for you

c = Child()
del c
# output: Child cleanup
# output: Parent cleanup

weakref.finalize as a Safer Alternative

weakref.finalize (Python 3.4+) registers a callback that is guaranteed to run when an object is about to be finalized, even if the object participates in a reference cycle.

import weakref

class DatabaseConnection:
    def close(self):
        print("Connection closed")

conn = DatabaseConnection()
finalizer = weakref.finalize(conn, DatabaseConnection.close, conn)

# Callback runs when conn is garbage collected
del conn
# output: Connection closed

Key advantages over __del__:

  • Callbacks run even for cycles containing the object
  • detach() lets you cancel the callback explicitly before the object is collected
  • No need to manually call super().__del__()
  • More explicit and easier to reason about
# Cancelling the finalizer before collection
finalizer.detach()  # callback will not run

Summary Table

Property__del__
Called whenObject is garbage collected (non-deterministic)
Guaranteed on interpreter exitNo
Handles reference cyclesNo — cycles with __del__ go to gc.garbage
ExceptionsPrinted to stderr, not raised
Parent __del__ called automaticallyNo — must call super().__del__() manually
Works with with statementNo — use __enter__ / __exit__
Python 3 recommended alternativeweakref.finalize or context managers

See Also