Complete guide to Python's getattr function covering attribute access, dynamic attribute lookup, and practical examples.
Last modified April 11, 2025
This comprehensive guide explores Python’s getattr function, which provides dynamic attribute access. We’ll cover basic usage, default values, method calling, and practical examples of dynamic attribute lookup.
The getattr function returns the value of a named attribute of an object. If the attribute doesn’t exist, it returns the default value or raises an AttributeError.
Key characteristics: takes an object, attribute name string, and optional default value. It’s Python’s built-in way to access attributes dynamically at runtime.
Here’s simple usage showing how getattr can access object attributes just like dot notation but with dynamic attribute names.
basic_getattr.py
class Person: def init(self, name, age): self.name = name self.age = age
p = Person(“Alice”, 30)
print(p.name) # Alice
print(getattr(p, ’name’)) # Alice print(getattr(p, ‘age’)) # 30
This example shows equivalent ways to access attributes. The getattr version allows the attribute name to be determined at runtime as a string.
While dot notation is preferred for known attributes, getattr enables dynamic attribute lookup which is powerful for flexible code.
getattr can provide a default value when an attribute doesn’t exist, preventing AttributeError exceptions. This example demonstrates safe attribute access.
default_value.py
class Config: def init(self): self.theme = “dark” self.font_size = 12
config = Config()
print(getattr(config, ’theme’, ’light’)) # dark (exists) print(getattr(config, ’language’, ’en’)) # en (default) print(getattr(config, ‘font_size’, 14)) # 12 (exists)
When the attribute exists, getattr returns its value. When it doesn’t exist, it returns the default value instead of raising an error.
This pattern is useful for configuration systems where missing settings should fall back to defaults without crashing the program.
getattr can retrieve methods dynamically, enabling runtime determination of which method to call. This example shows polymorphic behavior.
method_calling.py
class Calculator: def add(self, a, b): return a + b
def subtract(self, a, b):
return a - b
def execute(self, operation, a, b):
method = getattr(self, operation)
return method(a, b)
calc = Calculator() print(calc.execute(‘add’, 5, 3)) # 8 print(calc.execute(‘subtract’, 5, 3)) # 2
The execute method uses getattr to dynamically select which operation method to call based on the operation name string.
This technique is common in command pattern implementations and plugin systems where behavior is determined at runtime.
getattr can be combined with other Python features to access nested attributes dynamically. This example shows deep attribute access.
nested_attributes.py
class Address: def init(self, city): self.city = city
class User: def init(self, name, address): self.name = name self.address = address
addr = Address(“New York”) user = User(“Bob”, addr)
attr_path = ‘address.city’ parts = attr_path.split(’.’) result = user for part in parts: result = getattr(result, part)
print(result) # New York
This code splits a dotted attribute path and uses getattr in a loop to traverse nested objects. It’s similar to how Django’s ORM works.
For production code, you’d want to add error handling for missing attributes at any level in the path.
getattr can be used to implement sophisticated fallback mechanisms when combined with getattr. This example shows a proxy pattern.
fallback.py
class DataProxy: def init(self, data): self._data = data
def __getattr__(self, name):
# Try to get from _data first, then use default
try:
return getattr(self._data, name)
except AttributeError:
return f"Default {name}"
class Data: def init(self, value): self.value = value
data = Data(42) proxy = DataProxy(data)
print(proxy.value) # 42 (from _data) print(proxy.unknown) # Default unknown
The proxy first tries to get attributes from the wrapped object, then falls back to a default value. This demonstrates getattr’s role in Python’s attribute lookup chain.
This pattern is useful for decorators, adapters, and other proxy objects that need to forward most attribute access.
Prefer direct access: Use dot notation when attribute names are known
Use for dynamism: Use getattr when attribute names are determined at runtime
Provide defaults: Always consider using the default parameter for safety
Combine with hasattr: Check existence first if default isn’t appropriate
Document behavior: Clearly document dynamic attribute access patterns
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.