ZetCode

Python __delattr__ Method

Last modified April 8, 2025

This comprehensive guide explores Python's __delattr__ method, the special method invoked during attribute deletion. We'll cover basic usage, attribute protection, descriptor interaction, and practical examples.

Basic Definitions

The __delattr__ method is called when an attribute deletion is attempted on an object. It intercepts all del obj.attr operations. This allows customization of attribute deletion behavior.

Key characteristics: it receives the attribute name as string, must call super().__delattr__() for normal deletion, and can prevent deletion of specific attributes. It works with __setattr__ and __getattr__ for full attribute control.

Basic __delattr__ Implementation

Here's a simple implementation showing how __delattr__ intercepts attribute deletion. The method is called whenever del is used on an instance attribute.

basic_delattr.py
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __delattr__(self, name):
        print(f"Deleting attribute: {name}")
        super().__delattr__(name)

p = Person("Alice", 30)
del p.age  # Triggers __delattr__
print(hasattr(p, 'age'))  # False

This example shows the basic interception of attribute deletion. The method prints a message before delegating to the parent class's implementation for actual deletion. Without calling super, the attribute wouldn't be deleted.

The super().__delattr__(name) call is crucial - it performs the actual attribute removal from the instance's __dict__.

Preventing Attribute Deletion

__delattr__ can protect certain attributes from being deleted by raising an AttributeError when deletion is attempted.

protected_attrs.py
class ProtectedData:
    def __init__(self, data, protected=False):
        self.data = data
        self.protected = protected
    
    def __delattr__(self, name):
        if name == 'data' and self.protected:
            raise AttributeError("Cannot delete protected attribute 'data'")
        super().__delattr__(name)

pd = ProtectedData("secret", protected=True)
# del pd.data  # Raises AttributeError
del pd.protected  # Works fine

This class prevents deletion of the data attribute when the protected flag is True. Attempting to delete it raises an AttributeError with a custom message.

This pattern is useful for creating classes with critical attributes that shouldn't be accidentally deleted during program execution.

Logging Attribute Deletion

__delattr__ can log attribute deletions for debugging or auditing purposes, tracking when and which attributes are removed.

logging_deletions.py
class LoggedDeletions:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)
    
    def __delattr__(self, name):
        print(f"LOG: Deleting attribute '{name}' at {time.ctime()}")
        super().__delattr__(name)

import time
obj = LoggedDeletions(x=10, y=20)
del obj.x  # Logs the deletion
print(vars(obj))  # Shows remaining attributes

This implementation logs all attribute deletions with a timestamp. The actual deletion still occurs via the parent class's implementation after logging.

Such logging can be valuable for debugging complex object lifecycles or monitoring sensitive data handling in applications.

Descriptor Interaction with __delattr__

When working with descriptors, __delattr__ allows custom behavior when descriptor attributes are deleted, complementing __delete__.

descriptor_delattr.py
class Descriptor:
    def __delete__(self, instance):
        print("Descriptor __delete__ called")

class MyClass:
    desc = Descriptor()
    
    def __delattr__(self, name):
        print(f"MyClass __delattr__ for {name}")
        super().__delattr__(name)

obj = MyClass()
del obj.desc  # Calls both methods

This example shows the interaction between __delattr__ and descriptor's __delete__. Both methods are called when deleting a descriptor attribute, with __delattr__ called first.

The order is: __delattr__ intercepts the deletion, then the descriptor's __delete__ is called if present, and finally the actual attribute removal occurs.

Dynamic Attribute Cleanup

__delattr__ can perform additional cleanup when attributes are deleted, such as closing files or releasing resources associated with them.

cleanup_delattr.py
class ResourceHolder:
    def __init__(self):
        self.file = open('temp.txt', 'w')
        self.cache = {}
    
    def __delattr__(self, name):
        if name == 'file' and hasattr(self, 'file'):
            print("Closing file before deletion")
            getattr(self, 'file').close()
        super().__delattr__(name)

rh = ResourceHolder()
del rh.file  # Closes the file first
# File is now properly closed before deletion

This class ensures proper cleanup when file attributes are deleted. The __delattr__ method checks if the attribute being deleted is a file and closes it before proceeding with deletion.

This pattern helps prevent resource leaks when attributes holding resources are deleted from instances.

Best Practices

Source References

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.