Concise way to getattr() and use it if not None in Python

Question:

I am finding myself doing the following a bit too often:

attr = getattr(obj, 'attr', None)
if attr is not None:
    attr()
    # Do something, either attr(), or func(attr), or whatever
else:
    # Do something else

Is there a more pythonic way of writing that? Is this better? (At least not in performance, IMO.)

try:
    obj.attr() # or whatever
except AttributeError:
    # Do something else
Asked By: Oliver Zheng

||

Answers:

There is another nice idiom:

if hasattr(obj, 'attr'):
    ...something...
else:
    ...something else...

From the two options you posted I prefer the first one. The notion of throwing exceptions when accessing members just do not seem the thing the exceptions were meant to be used for.

Answered By: pajton

Using try/except is generally considered more pythonic. It is also more efficient if obj does have the attribute, since it eliminates the test – try blocks have no overhead if the exception is not thrown. On the other hand it is less efficient if obj does not have the attribute since it will have the overhead of throwing and catching the exception.

Answered By: Dave Kirby

The try/except alternative, as you code it, might accidentally cause an AttributeError caused by problems in anything that attr() is calling, to be caught. If you want to code with try/except, which is reasonable and quite well performing if it’s rare for the attribute to be missing, use:

try:
  attr = obj.attr
except AttributeError:
  dosome(thingelse)
else:
  attr()

this will not cause “accidental catching” as above. As to which approach is preferable, I generally go with the exception-catching approach – “EAFP”, “it’s Easier to Ask Forgiveness than Permission” (a motto often attributed to Admiral Grace Hopper, the driving force behind COBOL and CODASYL) definitely applies well to Python;-).

Answered By: Alex Martelli

Ah, it depends on the exact code. Your two tools:

  • hasattr(obj, ‘attr’) return True if and only if obj.attr exists.
  • getattr(obj, ‘attr’, other_value) returns obj.attr if it exists, else other_value
  • try a = obj.attr/except failure()/else do_something(a) when performance beats readability.

Here are the most common cases:

 the_name = getattr(user, 'name', '<Unknown User>')
 user.name = getattr(user, 'name', '<Unknown User>')
 if not hasattr(name, 'user'):
    try_asking_again()
 name = user.name if hasattr(user, 'name') else do_expensive_name_lookup(user)

To better understand the whole process, look at this snippet:

class Thing():
    def __init__(self):
        self.a = 'A'

    def __getattr__(self, attr):
        if attr == "b":
            return "B"
        else:
            raise AttributeError("Thing instance has no attribute '" + attr + "'")

item = Thing()
print "hasattr(a) is " + str(hasattr(item, "a"))
print "a is " + item.a
print "hasattr(b) is " + str(hasattr(item, "b"))
print "b is " + item.b
out = "c is " + item.c if hasattr(item, "c") else "No C"
print out
print "and c is also " + getattr(item, "c", "Not Assigned")
print "c throws an Attribute exception " + item.c

which has this output:

hasattr(a) is True
a is A
hasattr(b) is True
b is B
No C
and c is also Not Assigned
Traceback (most recent call last):
  File "attr_snippet.py", line 23, in <module>
    print "c throws an Attribute exception " + item.c
  File "attr_snippet.py", line 9, in __getattr__
    raise AttributeError("Thing instance has no attribute '" + attr + "'")
AttributeError: Thing instance has no attribute 'c'
Answered By: Charles Merriam

Since you are calling the attr, you could just do:

def default_action():
    # do something else

action = getattr(obj, 'attr', default_action)

action()
Answered By: Joe Koberg

Similar to Joe’s answer, but shorter:

getattr(obj, 'attr', lambda: None)()
Answered By: Valentin Lorentz
One liner:

object.attr() if hasattr(object, 'attr') else None

Explanation from the docs

hasattr(object, name: str)

The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an AttributeError or not.)

Answered By: Mark
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.