hasattr()

Check whether an object has an attribute — often the wrong tool. Prefer try/except or duck typing when the attribute might be a property with side effects.

Built-in functionPython 1.0+
Common call
if hasattr(obj, "close"):
Returns
True or False
Replaces
try: getattr(obj, name) except AttributeError: ...
Watch out
a property that raises DURING access returns True if it raises AttributeError, False otherwise — subtle
hasattr(objectobjectAny object. hasattr walks its class hierarchy to find the attribute.type: Any · required, namenameThe attribute name as a string. Not the name as a Python identifier — a runtime string.type: str · required)
bool

Parameters

NameTypeRequiredDescription
objectAnyyesAny object. hasattr walks its class hierarchy to find the attribute.
namestryesThe attribute name as a string. Not the name as a Python identifier — a runtime string.

Return value

boolTrue if getattr(object, name) would succeed. Implemented as a getattr call wrapped in try/except AttributeError. Any OTHER exception raised during attribute access propagates.

Common patterns

Optional-method dispatch
Call an optional method only if it exists.
if hasattr(handler, "on_close"):
    handler.on_close()
Feature detection
Check whether a module or class supports a newer API.
if hasattr(concurrent.futures, "InterpreterPoolExecutor"):
    ...   # 3.14+
Guard before setattr
Refuse to overwrite an existing attribute unless expected.
if hasattr(obj, name) and not force:
    raise ValueError(f"{name} already exists")
Prefer try/except for "probably has it" cases
When you expect the attribute to exist, EAFP style is cleaner and faster.
try:
    result = obj.method()
except AttributeError:
    result = fallback

Examples

1. str has upper
hasattr(str, "upper")
Returns
True
2. str no append
hasattr(str, "append")
Returns
False
3. list has append
hasattr(list, "append")
Returns
True
4. dict has keys
hasattr(dict, "keys")
Returns
True
5. Instance check
hasattr("hello", "upper")
Returns
True # instances see class attrs
6. Missing returns False
hasattr({}, "does_not_exist")
Returns
False

Pitfalls

1. A property that RAISES AttributeError silently returns False
The classic hasattr gotcha. If a property (or __getattr__) internally raises AttributeError — for any reason, even a bug — hasattr returns False rather than letting you see the real error.
Bug hidden
@property
def expensive(self):
    return self.does_not_exist   # AttributeError

hasattr(obj, "expensive")
False # bug looks like "attribute missing"
Try/except with logging
try:
    val = obj.expensive
except AttributeError as e:
    log.warning("no expensive: %s", e)
error visible
2. hasattr triggers property access
Properties have side effects. hasattr calls the property to see whether it raises — expensive properties are computed just to check existence. Use `hasattr(type(obj), name)` for cheap class-level checks.
Property triggered
hasattr(user, "expensive_computed_field")
True — but computed the value
Check the class
hasattr(type(user), "expensive_computed_field")
True — no computation
3. Instance attributes vs class attributes
hasattr(obj, name) is True whether the attribute is on the instance or on any class in the MRO. If you specifically want an instance attribute, check obj.__dict__ or use vars().
Class attr counts
class C: shared = 1
hasattr(C(), "shared")
True — from the class
Instance-only check
"shared" in vars(C())
False
4. Only AttributeError is caught — other exceptions propagate
Since Python 3.2, hasattr only swallows AttributeError. Any other exception (TypeError, KeyError, ...) raised during attribute access propagates, which is usually the correct behavior.
Old assumption
hasattr(obj, name)   # in Python 2, ate all exceptions
True/False even on bugs
3.x is more honest
# TypeError from a broken property will now raise
exposes real errors

When to use

Use it
  • Optional-method dispatch — call it if it exists
  • Feature detection across Python versions or libraries
  • Guarding setattr against accidental overwrite
  • Duck-typing checks against structural protocols (though isinstance with collections.abc is often better)
Reach for something else
  • Expected attribute → try/except is cleaner and cheaper
  • Property that might raise → try/except with logging exposes real bugs
  • Instance-only attribute check → use vars() or obj.__dict__
  • Expensive properties → check the class instead of the instance

Notes

Complexity
O(mro depth) — walks the class hierarchy
Return
bool — True or False
CPython impl
Python/bltinmodule.c :: builtin_hasattr — wraps PyObject_GetAttr
Memory
No allocation beyond the attribute lookup
Thread-safe
Depends on whether attribute access is safe for the object

FAQ

hasattr returns True or False. getattr with a default returns the value or the default. If you need the value, use getattr — do not check with hasattr and then fetch with getattr.

History

1.0
hasattr() has been a builtin since Python 1.0.
3.2
Only AttributeError is swallowed; other exceptions propagate. Previously (Python 2 / early 3), all exceptions returned False.