Python getattr(): Read Attributes with Safe Defaults

Quick answer: getattr(obj, name, default) reads a named attribute dynamically. Use it at boundaries where the name is genuinely dynamic, choose a deliberate default for optional attributes, and distinguish a missing attribute from an existing attribute whose value is None with a unique sentinel.

Python Pool infographic showing getattr object attribute name default and validation flow
getattr is useful at dynamic boundaries, but a default should reflect an optional attribute rather than conceal a broken object contract.

getattr() is a built-in Python function that reads an attribute from an object by name. It is most useful when the attribute name is known at runtime instead of being written directly with dot notation.

The basic form is getattr(object, name). The optional third argument is a default value returned when the attribute does not exist. Without that default, Python raises AttributeError. Dynamic reads often pair with dynamic writes; Python setattr() Function Guide explains setattr(), validation, properties, and when a dictionary is clearer.

The official Python getattr documentation defines the built-in function, and the official hasattr documentation explains the related existence check.

Read An Attribute By Name

Dot notation is best when the attribute name is fixed in the source code. getattr() is best when the name comes from configuration, a column choice, or another runtime decision.

class User:
    def __init__(self, name, role):
        self.name = name
        self.role = role

user = User("Maya", "admin")

print(getattr(user, "name"))
print(getattr(user, "role"))

This produces the same values as user.name and user.role, but the attribute name is passed as a string.

Use dot notation when possible because it is easier for readers and tools to follow. Reach for getattr() when the code genuinely needs a dynamic name.

Provide A Default Value

The third argument prevents AttributeError when an optional attribute is missing.

class Profile:
    def __init__(self, username):
        self.username = username

profile = Profile("nora")

print(getattr(profile, "username", "unknown"))
print(getattr(profile, "email", "not provided"))

The default should be a value the rest of the code can handle. Common defaults include None, an empty string, a sentinel object, or a domain-specific fallback.

Do not use a default to hide a real bug. If an attribute should always exist, let the exception reveal the broken object.

Python Pool infographic showing an object, attribute name, getattr, and returned value
getattr reads an attribute by a string name.

Select Fields Dynamically

getattr() is useful for selecting one attribute from an allowed set of names.

class Article:
    def __init__(self, title, views):
        self.title = title
        self.views = views

article = Article("Python getattr", 1200)
field = "views"

if field in {"title", "views"}:
    print(getattr(article, field))

The allowlist matters. Do not pass untrusted names directly into getattr() and then act on the result without checking what names are allowed.

This pattern works well for sorting, display columns, export choices, and small command handlers where the accepted names are known.

Call A Method By Name

If the attribute is a method, getattr() returns a callable object. You can then check it and call it.

class Greeter:
    def hello(self):
        return "hello"

    def goodbye(self):
        return "goodbye"

greeter = Greeter()
action = "hello"
method = getattr(greeter, action)

if callable(method):
    print(method())

This is a compact dispatch pattern, but it should still use an allowlist for names that come from outside the program.

For public commands, a dictionary that maps command names to functions is often clearer. Use getattr() when the object model is already the right source of behavior.

Python Pool infographic mapping a missing attribute through getattr to a default value
The optional default avoids AttributeError when a missing attribute is acceptable.

Compare getattr And hasattr

hasattr() answers whether an attribute can be read. getattr() reads it. A sentinel default can do both in one lookup.

class Settings:
    timeout = 30

settings = Settings()
missing = object()

value = getattr(settings, "timeout", missing)

if value is missing:
    print("missing")
else:
    print(value)

The sentinel approach distinguishes a missing attribute from a real value such as None, 0, or an empty string.

Use hasattr() when you only need a yes-or-no answer. Use getattr() when you need the value itself.

Avoid Unsafe Lookup

Dynamic lookup can expose attributes that were never meant to be commands. Keep accepted names explicit.

class Report:
    def summary(self):
        return "summary ready"

    def delete(self):
        return "not allowed here"

report = Report()
actions = {"summary"}
requested = "summary"

if requested in actions:
    print(getattr(report, requested)())

This keeps the dynamic behavior narrow. Without the allowlist, a caller might reach methods that should not be available in that context.

Know When Not To Use It

getattr() is powerful, but it can make code harder to trace when used for ordinary attribute access. If the name is fixed and clear, user.name is better than getattr(user, "name").

Static analysis tools, autocomplete, and readers all understand dot notation more easily. Heavy dynamic lookup can hide spelling mistakes until runtime and make refactoring more fragile.

Be especially careful with broad exception handling. Catching AttributeError around a large block can hide errors raised inside property methods. Prefer a default argument, a small lookup, or a sentinel when the missing attribute is expected.

Properties can also run code when accessed. Calling getattr() on a property is not just reading stored data; it may perform calculation, validation, or I/O depending on how the class was written. Treat dynamic property access with the same care as direct property access.

For dictionaries, use normal key access or dict.get(). getattr() reads object attributes, not dictionary keys, so it is the wrong tool for plain mapping data unless the object intentionally exposes attributes.

Readable code should stay the priority.

The practical rule is to prefer dot notation for fixed attributes, use getattr() for runtime names, supply a default only when missing attributes are expected, and validate names before calling methods dynamically.

Python Pool infographic comparing direct access, getattr, configuration names, and dispatch
Dynamic access can support configuration-driven dispatch when names are trusted and validated.

Read A Dynamic Name

When a configuration value or plugin name determines the attribute, getattr avoids a chain of special cases. Validate the name before reading it if it came from outside the program.

class User:
    display_name = "Ada"

user = User()
name = getattr(user, "display_name")
print(name)

Use A Sentinel For Missing Values

A default of None is ambiguous when the attribute can legitimately contain None. A private object lets the caller tell absence apart from an existing empty value.

missing = object()
value = getattr(object(), "optional", missing)
if value is missing:
    print("attribute is absent")
Python Pool infographic testing defaults, properties, callables, security, and validation
Check properties, callable values, untrusted names, defaults, and security boundaries.

Check Callables Before Calling

getattr returns the attribute object, including a method. Check the callable contract when the attribute name is dynamic, and surface an invalid plugin instead of swallowing every exception.

class Plugin:
    def run(self):
        return "ok"

method = getattr(Plugin(), "run", None)
if not callable(method):
    raise TypeError("plugin run attribute is not callable")
print(method())

Prefer Direct Access For Required Fields

Direct access communicates that an attribute is required and lets AttributeError reveal a broken object contract. getattr with a default should not be used to hide a programming error.

class Settings:
    retries = 3

settings = Settings()
print(settings.retries)

Python’s getattr() documentation defines default behavior for missing attributes. Related references include None values, iteration patterns, and testing object contracts.

For related object contracts, compare None values, iteration patterns, and testing when reading dynamic attributes.

Frequently Asked Questions

What does getattr do in Python?

getattr returns a named attribute from an object and can return a default when the attribute is missing.

What is the difference between a missing attribute and None?

A missing attribute is absent; an existing attribute can legitimately contain None, so use a unique sentinel when the distinction matters.

Can getattr call a method?

getattr returns the method object; call it explicitly only after checking that the callable contract is expected.

When should I use direct attribute access?

Use direct access when the attribute name is known and required so errors are visible and type checking remains clear.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted