Complete guide to Python's hasattr function covering object introspection, attribute checking, and practical examples.
Last modified April 11, 2025
This comprehensive guide explores Python’s hasattr function, which checks for attribute existence in objects. We’ll cover basic usage, class inheritance, dynamic attributes, and practical examples of introspection.
The hasattr function checks if an object has a given attribute. It returns True if the attribute exists, False otherwise. This is safer than direct attribute access with try/except.
Key characteristics: takes an object and attribute name string as arguments. Works with all Python objects including classes, instances, modules, and built-in types. Part of Python’s introspection capabilities.
Here’s simple usage showing how hasattr checks for attributes in different types of objects including classes and instances.
basic_hasattr.py
class Person: def init(self, name): self.name = name
p = Person(“Alice”)
print(hasattr(p, ’name’)) # True print(hasattr(p, ‘age’)) # False
print(hasattr(Person, ‘init’)) # True print(hasattr(Person, ‘species’)) # False
This example shows hasattr checking both instance and class attributes. It safely checks for existence without raising AttributeError.
The function works with any attribute name including methods (like init) and regular data attributes (like name).
hasattr works with inheritance hierarchies, checking both the instance and its class hierarchy for attributes. This example demonstrates.
inheritance.py
class Animal: def init(self): self.kingdom = “Animalia”
class Dog(Animal): def init(self, name): super().init() self.name = name
def bark(self):
return "Woof!"
buddy = Dog(“Buddy”)
print(hasattr(buddy, ’name’)) # True (instance) print(hasattr(buddy, ‘kingdom’)) # True (parent class) print(hasattr(buddy, ‘bark’)) # True (class method) print(hasattr(buddy, ‘species’)) # False (nonexistent)
hasattr correctly identifies attributes from the instance, its class, and parent classes. This makes it useful for checking API compliance.
The function follows Python’s attribute lookup rules, checking the full method resolution order (MRO) for classes.
hasattr can check for dynamically added attributes, including those created with setattr or through property decorators.
dynamic.py
class DynamicAttributes: def init(self): self.initial = “value”
@property
def computed(self):
return 42
obj = DynamicAttributes() setattr(obj, ‘dynamic’, ’new value’)
print(hasattr(obj, ‘initial’)) # True (regular) print(hasattr(obj, ‘computed’)) # True (property) print(hasattr(obj, ‘dynamic’)) # True (setattr) print(hasattr(obj, ‘missing’)) # False
This shows hasattr working with different attribute types. It detects regular attributes, properties, and dynamically added attributes.
Properties are treated like regular attributes, demonstrating Python’s uniform attribute access principle.
While hasattr is designed to prevent AttributeError, it can’t catch all attribute-related issues. This example shows edge cases.
errors.py
class Problematic: def init(self): self._value = 10
@property
def value(self):
return self._value
@value.setter
def value(self, val):
if val < 0:
raise ValueError("Must be positive")
self._value = val
def method(self):
raise RuntimeError("Intentional error")
obj = Problematic()
print(hasattr(obj, ‘missing’)) # False (safe) print(hasattr(obj, ‘value’)) # True (property exists)
try: obj.value = -5 except ValueError as e: print(f"Caught: {e}")
print(hasattr(obj, ‘method’)) # True (method exists)
hasattr only checks for attribute existence, not whether the attribute can be successfully accessed. Property setters and methods may still raise exceptions.
This demonstrates that hasattr is not a complete validation tool, but rather an existence checker.
A common use for hasattr is checking for optional features or plugins in a modular system. This example shows a simple plugin check.
plugins.py
class BasicViewer: def show(self, content): print(f"Basic: {content}")
class AdvancedViewer(BasicViewer): def show(self, content): print(f"Advanced: {content}")
def save(self, content, filename):
with open(filename, 'w') as f:
f.write(content)
def process_content(viewer, content, filename=None): viewer.show(content)
if hasattr(viewer, 'save') and filename:
print("Saving content...")
viewer.save(content, filename)
else:
print("Save feature not available")
basic = BasicViewer() advanced = AdvancedViewer()
process_content(basic, “Hello”) # Basic only process_content(advanced, “Hello”, “output.txt”) # Uses save
This demonstrates using hasattr to check for optional features. The system works with both basic and advanced viewers without type checking.
This duck-typing approach is more flexible than explicit type checks and follows Python’s EAFP (Easier to Ask for Forgiveness than Permission) principle.
Prefer over try/except: Use hasattr for simple existence checks
Document expected attributes: Clearly document interfaces
Consider properties: Remember hasattr checks existence, not usability
Use with duck typing: Check capabilities rather than types
Avoid overuse: Sometimes direct access with try/except is clearer
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.