Quark’s Outlines: Python Customizing Attribute Access
Overview, Historical Timeline, Problems & Solutions
An Overview of Python Customizing Attribute Access
What does it mean to customize attribute access in Python?
When you use x.name in Python, the language looks for that name in the object’s data. This is called attribute access. You can customize attribute access in Python by defining special methods in a class.
You can tell Python what to do when someone tries to get, set, or delete an attribute. These methods are __getattr__, __setattr__, and __delattr__. They let you control how attributes behave at runtime.
Python lets you change how attributes work using special methods.
class Example:
def __getattr__(self, name):
return f"Attribute {name} not found"
x = Example()
print(x.foo)
# prints:
# Attribute foo not found
Python did not find foo, so it called __getattr__. The method returned a message instead of raising an error.
What does __getattr__ do in Python?
Python calls __getattr__ only when it cannot find the attribute in the usual places. That means the attribute is not in the instance and not in its class.
You use __getattr__ to compute or simulate values that are not stored directly. This is useful when building proxy objects, virtual fields, or fallbacks.
Python uses __getattr__ when a normal lookup fails.
class Example:
def __getattr__(self, name):
return 42
x = Example()
print(x.anything)
# prints:
# 42
This class returns 42 for any missing attribute.
What does __setattr__ do in Python?
Python calls __setattr__ every time you assign to an attribute. This method overrides the normal behavior. If you do not store the value in the object’s dictionary directly, you will get a recursive call.
To avoid this, use self.__dict__[name] = value. This changes the data without calling __setattr__ again.
Python lets you intercept assignments with __setattr__.
class Track:
def __setattr__(self, name, value):
print(f"Setting {name} = {value}")
self.__dict__[name] = value
x = Track()
x.speed = 100
# prints:
# Setting speed = 100
The __setattr__ method gives you full control over how attributes are stored.
What does __delattr__ do in Python?
Python calls __delattr__ when you delete an attribute using del x.name. If you define __delattr__, you can log or change what happens when data is removed.
Python lets you customize deletion with __delattr__.
class Cleanup:
def __delattr__(self, name):
print(f"Deleting {name}")
del self.__dict__[name]
x = Cleanup()
x.a = 10
del x.a
# prints:
# Deleting a
This example shows how Python routes deletion through the special method.
A Historical Timeline of Python Customizing Attribute Access
Where do Python’s attribute access hooks come from?
Python’s model for attribute access comes from object-oriented systems in older languages. Over time, Python added methods that let you override default behavior. These methods help you build frameworks, wrappers, and new object systems.
People built object models that respond to attribute access
1980 — Smalltalk and Lisp OOP used dynamic dispatch and method lookup to model behavior flexibly.
1983 — C++ introduced operator overloading that included overloading for member access and assignment.
People gave Python custom hooks for attributes
1991 — Python 0.9.0 supported attribute lookup via dictionaries for object state and access.
2000 — __getattr__, __setattr__, and __delattr__ formalized in Python 2.0 to override standard behavior.
2001 — Python descriptor protocol introduced to offer deeper control for classes and fields.
2015 — Property decorators and metaclass support expanded for class-level attribute logic.
2025 — Python access model remains stable with these hooks as the base for more advanced tools.
Problems & Solutions with Python Customizing Attribute Access
How do you use Python attribute hooks the right way?
Python gives you special methods to take control of what happens when an attribute is read, written, or removed. These problems show how to use that control to add features and avoid common mistakes.
Problem: How do you provide fallback values for missing attributes in Python?
You are building a lightweight object. Some attributes might not exist yet, but you do not want the code to fail when they are missing. You want to return a default value instead of raising an error.
Solution: Python calls __getattr__ when an attribute does not exist.
Python lets you return fallback values using __getattr__.
class Safe:
def __getattr__(self, name):
return f"{name} not set"
x = Safe()
print(x.color)
# prints:
# color not set
This object returns a message instead of crashing when an attribute is missing.
Problem: How do you log changes to an object's fields in Python?
You are tracking a program’s state. You want to print a message every time a value changes, so you can see how your object is used. You want to do this without repeating print statements.
Solution: Python calls __setattr__ every time a field is updated.
Python lets you log updates using __setattr__.
class Watch:
def __setattr__(self, name, value):
print(f"{name} set to {value}")
self.__dict__[name] = value
w = Watch()
w.level = 5
# prints:
# level set to 5
This helps you understand when and how your data changes.
Problem: How do you keep some attributes read-only in Python?
You are building a configuration object. Some values should never change after the object is created. You want to raise an error if someone tries to update those fields.
Problem: You want to stop certain fields from being reassigned.
Solution: Python __setattr__ can reject changes based on the attribute name.
Python lets you prevent changes using rules in __setattr__.
class Locked:
def __init__(self):
self.__dict__['locked'] = True
def __setattr__(self, name, value):
if name == "locked":
raise AttributeError("Cannot modify 'locked'")
self.__dict__[name] = value
x = Locked()
x.mode = "test"
x.locked = False
# prints:
# Traceback (most recent call last):
# AttributeError: Cannot modify 'locked'
The class refuses to change protected values after they are set.
Problem: How do you respond when someone deletes an attribute in Python?
You have an object with important fields. If someone deletes a field, you want to log the deletion or stop it. You do not want to let data disappear silently.
Problem: You want to handle or block attribute deletion.
Solution: Python calls __delattr__ when del is used on a field.
Python lets you respond to deletion with __delattr__.
class Guarded:
def __delattr__(self, name):
if name == "key":
raise AttributeError("Cannot delete key")
print(f"Deleted {name}")
del self.__dict__[name]
x = Guarded()
x.key = "value"
del x.key
# prints:
# Traceback (most recent call last):
# AttributeError: Cannot delete key
You control what happens when someone tries to remove part of your object.
Problem: How do you simulate virtual attributes in Python?
You are building a class that holds computed values. These values are not stored in the object, but you want users to access them as if they were attributes.
Problem: You want to define an attribute without storing it.
Solution: Python lets you return a value using __getattr__.
Python lets you simulate fields with __getattr__.
class Virtual:
def __getattr__(self, name):
if name == "area":
return self.width * self.height
raise AttributeError(name)
v = Virtual()
v.width = 4
v.height = 3
print(v.area)
# prints:
# 12
The area is not stored, but Python calculates it when asked.
Like, Comment, Share, and Subscribe
Did you find this helpful? Let me know by clicking the like button below. I'd love to hear your thoughts in the comments, too! If you want to see more content like this, don't forget to subscribe. Thanks for reading!
Mike Vincent is an American software engineer and app developer from Los Angeles, California. More about Mike Vincent
Top comments (0)