__del__
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 runs | Non-deterministic — at GC time | Deterministic — immediately on block exit |
| Interpreter shutdown | Not called | Called |
| Exceptions | Printed to stderr, not raised | Propagated normally |
| Reference cycles | Cannot 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 when | Object is garbage collected (non-deterministic) |
| Guaranteed on interpreter exit | No |
| Handles reference cycles | No — cycles with __del__ go to gc.garbage |
| Exceptions | Printed to stderr, not raised |
Parent __del__ called automatically | No — must call super().__del__() manually |
Works with with statement | No — use __enter__ / __exit__ |
| Python 3 recommended alternative | weakref.finalize or context managers |
See Also
__enter__/__exit__— context manager protocolweakrefmodule — includesweakref.finalize