The hasattr(object, name) function checks whether an object possesses a specified attribute, returning True if present or False if missing.
Introspection & Duck Typing: By evaluating attribute existence dynamically via string names, hasattr() allows programs to safely adapt to heterogeneous objects and protocols without raising an AttributeError. To retrieve or assign attribute values dynamically, use sister built-in functions like getattr() and setattr(), or remove them with delattr().
The hasattr() function takes two arguments and evaluates to a boolean value:
has_attr = hasattr(object, name)
| Parameter | Type | Role & Behavioral Details |
|---|---|---|
object |
Any object | The target instance, class, or module being inspected. |
name |
str |
The attribute name as a string identifier. Passing non-string objects raises a TypeError. |
| Return Value | bool |
Returns True if the attribute exists on the object or its class hierarchy; otherwise False. |
You can check for instance attributes, class variables, and methods on any object:
class Animal:
species = "carnivores" # Class attribute
def __init__(self, name: str, age: int):
self.name = name
self.age = age
tiger = Animal("Ronald", 5)
# Existing instance attribute
print("Has age:", hasattr(tiger, "age"))
# Existing class attribute
print("Has species:", hasattr(tiger, "species"))
# Missing attribute returns False cleanly
print("Has height:", hasattr(tiger, "height"))
Output:
Has age: True
Has species: True
Has height: False
hasattr() Works 🔝Under the hood, CPython implements hasattr(obj, name) by calling getattr(obj, name) and checking for an exception:
# Conceptual implementation of hasattr() in Python
def custom_hasattr(obj, name: str) -> bool:
try:
getattr(obj, name)
return True
except AttributeError:
return False
Because it internally invokes getattr(), any custom __getattr__ or __getattribute__ methods defined on the target class will execute normally during the check.
hasattr() vs. getattr(): EAFP vs. LBYL 🔝In Python, choosing between hasattr() and getattr() with a default depends on whether you only need to verify existence or immediately consume the value:
| Pattern | Approach Style | Efficiency & Recommendation |
|---|---|---|
hasattr(obj, 'val') then obj.val |
LBYL (Look Before You Leap) | Performs two attribute lookups. Use when checking capability without consuming the value. |
val = getattr(obj, 'val', default) |
EAFP (Easier to Ask Forgiveness) | Performs one attribute lookup. Preferred when you need to read and use the value. |
class Config:
timeout = 30
cfg = Config()
# Pattern 1: hasattr() check before branch
if hasattr(cfg, "timeout"):
print("Timeout configured (hasattr):", cfg.timeout)
# Pattern 2: Single-step getattr() with default (more Pythonic)
timeout = getattr(cfg, "timeout", 60)
print("Effective timeout (getattr):", timeout)
Output:
Timeout configured (hasattr): 30
Effective timeout (getattr): 30
hasattr() inspects the object's entire inheritance hierarchy, including inherited methods, properties, and special dunder protocols:
class BaseDevice:
def connect(self):
return True
class SmartLight(BaseDevice):
def turn_on(self):
pass
light = SmartLight()
# Inherited method from BaseDevice
print("Has connect:", hasattr(light, "connect"))
# Checking callable method vs attribute
print("Is connect callable:", callable(getattr(light, "connect")))
# Checking built-in dunder protocols
print("Has __iter__ on list:", hasattr([1, 2], "__iter__"))
print("Has __iter__ on int:", hasattr(42, "__iter__"))
Output:
Has connect: True
Is connect callable: True
Has __iter__ on list: True
Has __iter__ on int: False
@property Side-Effect & Masking Gotcha 🔝Because hasattr() calls getattr(), inspecting a decorated @property actually executes the property getter code. If the getter throws an AttributeError internally, hasattr() will unexpectedly return False:
class Account:
@property
def balance(self):
print(">>> Property getter executed!")
return 1000
acc = Account()
# Checking hasattr triggers the getter!
print("Checking hasattr(acc, 'balance'):")
exists = hasattr(acc, "balance")
print("Result:", exists)
Output:
Checking hasattr(acc, 'balance'):
>>> Property getter executed!
Result: True
hasattr() checks on those objects.
Check whether an arbitrary object conforms to a file-like stream protocol before reading or writing:
def safe_stream_reader(source) -> str:
if hasattr(source, "read") and callable(source.read):
return source.read()
elif isinstance(source, str):
return source
else:
raise TypeError("Object does not support stream reading")
import io
stream = io.StringIO("Sample stream buffer data")
print("Stream result:", safe_stream_reader(stream))
print("String result:", safe_stream_reader("Raw string text"))
Output:
Stream result: Sample stream buffer data
String result: Raw string text
Safely close active connection handles without assuming a specific connection library:
def close_resource(resource):
if hasattr(resource, "close") and callable(resource.close):
resource.close()
return "Resource closed cleanly"
return "No close method available"
class SocketMock:
def close(self):
pass
print(close_resource(SocketMock()))
print(close_resource(123))
Output:
Resource closed cleanly
No close method available
hasattr(obj, name) must be a string. Passing an unquoted identifier like hasattr(tiger, age) treats age as a variable name and raises a NameError!
tiger = Animal("Ronald", 5)
# Correct: pass string literal
print("Valid check:", hasattr(tiger, "age"))
# Wrong: passing non-string argument raises TypeError
try:
hasattr(tiger, 123)
except TypeError as err:
print("TypeError caught:", err)
Output:
Valid check: True
TypeError caught: hasattr(): attribute name must be string
Practice dynamic attribute checks, duck typing protocols, and property inspection in our companion Jupyter Notebook:
Explore interactive code cells, verify stream duck typing protocols, test property getter side-effects, and run self-validating assertions.
View on GitHub Run in Google ColabRun these unit checks directly in Python or your local environment to verify hasattr() mechanics:
def test_hasattr_mechanics():
class Device:
brand = "Acme"
def __init__(self, sn: str):
self.sn = sn
dev = Device("SN-001")
assert hasattr(dev, "sn") is True
assert hasattr(dev, "brand") is True
assert hasattr(dev, "firmware") is False
# Dynamic addition reflection
setattr(dev, "firmware", "v1.0")
assert hasattr(dev, "firmware") is True
print("All hasattr() unit assertions passed! 100% verified.")
test_hasattr_mechanics()
Output:
All hasattr() unit assertions passed! 100% verified.
Retrieves the value of a named attribute from an object, with optional default fallback.
Dynamically assigns or updates a named attribute on an object instance.
Deletes a named attribute directly from an object instance.
Checks if an object is an instance or subclass of a specified class.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.