396

I read an article about the getattr function, but I still can't understand what it's for.

The only thing I understand about getattr() is that getattr(li, "pop") is the same as calling li.pop.

When and how do I use this exactly? The book said something about using it to get a reference to a function whose name isn't known until runtime, but when and why would I use this?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Terence Ponce
  • 9,123
  • 9
  • 31
  • 37

14 Answers14

350

Objects in Python can have attributes -- data attributes and functions to work with those (methods). Actually, every object has built-in attributes (try dir(None), dir(True), dir(...), dir(dir) in Python console).

For example you have an object person, that has several attributes: name, gender, etc.

You access these attributes (be it methods or data objects) usually writing: person.name, person.gender, person.the_method(), etc.

But what if you don't know the attribute's name at the time you write the program? For example you have attribute's name stored in a variable called attr_name.

if

attr_name = 'gender'

then, instead of writing

gender = person.gender

you can write

gender = getattr(person, attr_name)

Some practice:

Python 3.4.0 (default, Apr 11 2014, 13:05:11)

>>> class Person():
...     name = 'Victor'
...     def say(self, what):
...         print(self.name, what)
... 
>>> getattr(Person, 'name')
'Victor'
>>> attr_name = 'name'
>>> person = Person()
>>> getattr(person, attr_name)
'Victor'
>>> getattr(person, 'say')('Hello')
Victor Hello

getattr will raise AttributeError if attribute with the given name does not exist in the object:

>>> getattr(person, 'age')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'age'

But you can pass a default value as the third argument, which will be returned if such attribute does not exist:

>>> getattr(person, 'age', 0)
0

You can use getattr along with dir to iterate over all attribute names and get their values:

>>> dir(1000)
['__abs__', '__add__', ..., '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

>>> obj = 1000
>>> for attr_name in dir(obj):
...     attr_value = getattr(obj, attr_name)
...     print(attr_name, attr_value, callable(attr_value))
... 
__abs__ <method-wrapper '__abs__' of int object at 0x7f4e927c2f90> True
...
bit_length <built-in method bit_length of int object at 0x7f4e927c2f90> True
...

>>> getattr(1000, 'bit_length')()
10

A practical use for this would be to find all methods whose names start with test and call them.

Similar to getattr there is setattr which allows you to set an attribute of an object having its name:

>>> setattr(person, 'name', 'Andrew')
>>> person.name  # accessing instance attribute
'Andrew'
>>> Person.name  # accessing class attribute
'Victor'
>>>
warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • 14
    So it seems to me that `getattr(..)` should be used in 2 scenarios: 1. when the attribute name is a value inside of a variable (e.g. `getattr(person, some_attr)`) and 2. when we need to use the third positional argument for the default value (e.g. `getattr(person, 'age', 24)`). If I see a scenario like `getattr(person, 'age')` it seems to me that it is identical to `person.age` which leads me to think that `person.age` is more Pythonic. Is that correct? – wpcarro Oct 24 '16 at 22:01
  • 1
    @wpcarro both `person.age` and `getattr(person, "age")` are idiomatic to Python, so hard to make the case one is more Pythonic than the other. – qneill Jul 19 '20 at 02:01
  • 4
    "Readability counts". Certainly `person.age` is better than `getattr(person, "age")`. I makes sense to use `getattr` when you have attribute name in a variable. – warvariuc Jun 10 '21 at 13:55
234

getattr(object, 'x') is completely equivalent to object.x.

There are only two cases where getattr can be useful.

  • you can't write object.x, because you don't know in advance which attribute you want (it comes from a string). Very useful for meta-programming.
  • you want to provide a default value. object.y will raise an AttributeError if there's no y. But getattr(object, 'y', 5) will return 5.
pfabri
  • 885
  • 1
  • 9
  • 25
blue_note
  • 27,712
  • 9
  • 72
  • 90
  • 1
    Am I incorrect in thinking that the second bullet point is inconsistent with opening statement of the answer? – skoh Jul 02 '20 at 16:18
  • 4
    @skoh: well, actually, the opening statement mentions `getattr` with two parameters (which is equivalent), and the 2nd bullet mentions getattr with 3 parameters. Even if it was incosistent though, I would probably leave it, emphasis is more important. – blue_note Jul 02 '20 at 17:12
  • u lost me at "because you don't know in advance which attribute you want (it comes from a string)"..... – Ulf Gjerdingen Aug 21 '20 at 14:06
  • 2
    @UlfGjerdingen: think of javascript. `o.x` is equivalent to `o['x']`. But the second expression could be used with any `o[some_string]` that could be decided at runtime (eg, from user input or object inspection), while in the first expression, `x` is fixed. – blue_note Aug 21 '20 at 16:13
  • @blue_note and what is `object.x` – develarist Sep 15 '20 at 21:04
  • That's the attribute access of the object, just like in any object oriented language – blue_note Sep 15 '20 at 21:11
  • 7
    To revive a necro, another use case is when the identifier contains an illegal character like `.` or `-` (as I am dealing with now). `getattr(obj, 'some.val')` will work where obj.some.val will not. – Michael Oct 26 '20 at 05:00
  • Or rather than containing an illegal character, the attribute name could be a reserved word. To pre-empt the question, both this case and the punctuation case would happen either due to `setattr` having been used previously, or by hacking the object's `__dict__` directly. This can happen implicitly when using `types.SimpleNamespace` or `argparse.Namespace`. – Karl Knechtel Mar 27 '21 at 21:12
  • Does it work inside a class function like getattr(self, local_functionname)? – Jürgen K. Sep 06 '21 at 09:18
  • 1
    @JürgenK.: of course, `self` behaves just like any other object, the only difference is that it's passed automatically – blue_note Sep 06 '21 at 09:22
  • so 'self' as first argument doesn't need to be given? – Jürgen K. Sep 06 '21 at 09:31
  • @JürgenK.: not sure what you mean by "given". it automatically appears as an additional first argument when you call a method of an object, like `this` in eg java/c++, only shown explicitly. Regardless, that's general python behavior, unrelated to `getattr` – blue_note Sep 06 '21 at 09:35
124

For me, getattr is easiest to explain this way:

It allows you to call methods based on the contents of a string instead of typing the method name.

For example, you cannot do this:

obj = MyObject()
for x in ['foo', 'bar']:
    obj.x()

because x is not of the type builtin, but str. However, you CAN do this:

obj = MyObject()
for x in ['foo', 'bar']:
    getattr(obj, x)()

It allows you to dynamically connect with objects based on your input. I've found it useful when dealing with custom objects and modules.

Daniel Holmes
  • 1,952
  • 2
  • 17
  • 28
NuclearPeon
  • 5,743
  • 4
  • 44
  • 52
  • 4
    This is a pretty straight forward and precise answer. – user6037143 Jan 01 '19 at 17:27
  • what is `object.x` – develarist Sep 15 '20 at 21:05
  • 1
    @develarist The asker didn't have an example for me to base my answer off of, so `MyObject`, `obj`, and `x` (Class def, class instance and attribute respectively) are just examples/mockup data where you should fill in your own classes and attributes that you want to access. `foo`, `bar`, and `baz` are often used as placeholders in linux/unix/foss docs. – NuclearPeon Sep 15 '20 at 21:50
  • operator.methodcaller( ) is designed to do the same as in this example, calling a method defined with strings. I kind of prefer the implementation in the example. – Rub Nov 30 '21 at 23:09
45

A pretty common use case for getattr is mapping data to functions.

For instance, in a web framework like Django or Pylons, getattr makes it straightforward to map a web request's URL to the function that's going to handle it. If you look under the hood of Pylons's routing, for instance, you'll see that (by default, at least) it chops up a request's URL, like:

http://www.example.com/customers/list

into "customers" and "list". Then it searches for a controller class named CustomerController. Assuming it finds the class, it creates an instance of the class and then uses getattr to get its list method. It then calls that method, passing it the request as an argument.

Once you grasp this idea, it becomes really easy to extend the functionality of a web application: just add new methods to the controller classes, and then create links in your pages that use the appropriate URLs for those methods. All of this is made possible by getattr.

Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
16

Here's a quick and dirty example of how a class could fire different versions of a save method depending on which operating system it's being executed on using getattr().

import os

class Log(object):
    def __init__(self):
        self.os = os.name
    def __getattr__(self, name):
        """ look for a 'save' attribute, or just 
          return whatever attribute was specified """
        if name == 'save':
            try:
                # try to dynamically return a save 
                # method appropriate for the user's system
                return getattr(self, self.os)
            except:
                # bail and try to return 
                # a default save method
                return getattr(self, '_save')
        else:
            return getattr(self, name)

    # each of these methods could have save logic specific to 
    # the system on which the script is executed
    def posix(self): print 'saving on a posix machine'
    def nt(self): print 'saving on an nt machine'
    def os2(self): print 'saving on an os2 machine'
    def ce(self): print 'saving on a ce machine'
    def java(self): print 'saving on a java machine'
    def riscos(self): print 'saving on a riscos machine'
    def _save(self): print 'saving on an unknown operating system'

    def which_os(self): print os.name

Now let's use this class in an example:

logger = Log()

# Now you can do one of two things:
save_func = logger.save
# and execute it, or pass it along 
# somewhere else as 1st class:
save_func()

# or you can just call it directly:
logger.save()

# other attributes will hit the else 
# statement and still work as expected
logger.which_os()
Josh
  • 2,158
  • 18
  • 22
8

Other than all the amazing answers here, there is a way to use getattr to save copious lines of code and keeping it snug. This thought came following the dreadful representation of code that sometimes might be a necessity.

Scenario

Suppose your directory structure is as follows:

- superheroes.py
- properties.py

And, you have functions for getting information about Thor, Iron Man, Doctor Strange in superheroes.py. You very smartly write down the properties of all of them in properties.py in a compact dict and then access them.

properties.py

thor = {
    'about': 'Asgardian god of thunder',
    'weapon': 'Mjolnir',
    'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
    'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
    'weapon': 'Armor',
    'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
    'about': ' primary protector of Earth against magical and mystical threats',
    'weapon': 'Magic',
    'powers': ['magic', 'intellect', 'martial arts'],
}

Now, let's say you want to return capabilities of each of them on demand in superheroes.py. So, there are functions like

from .properties import thor, iron_man, doctor_strange


def get_thor_weapon():
    return thor['weapon']


def get_iron_man_bio():
    return iron_man['about']


def get_thor_powers():
    return thor['powers']

...and more functions returning different values based on the keys and superhero.

With the help of getattr, you could do something like:

from . import properties


def get_superhero_weapon(hero):
    superhero = getattr(properties, hero)
    return superhero['weapon']


def get_superhero_powers(hero):
    superhero = getattr(properties, hero)
    return superhero['powers']

You considerably reduced the number of lines of code, functions and repetition!

Oh and of course, if you have bad names like properties_of_thor for variables , they can be made and accessed by simply doing

def get_superhero_weapon(hero):
    superhero = 'properties_of_{}'.format(hero)
    all_properties = getattr(properties, superhero)
    return all_properties['weapon']

NOTE: For this particular problem, there can be smarter ways to deal with the situation, but the idea is to give an insight about using getattr in right places to write cleaner code.

unixia
  • 4,102
  • 1
  • 19
  • 23
4
# getattr

class hithere():

    def french(self):
        print 'bonjour'

    def english(self):
        print 'hello'

    def german(self):
        print 'hallo'

    def czech(self):
        print 'ahoj'

    def noidea(self):
        print 'unknown language'


def dispatch(language):
    try:
        getattr(hithere(),language)()
    except:
        getattr(hithere(),'noidea')()
        # note, do better error handling than this

dispatch('french')
dispatch('english')
dispatch('german')
dispatch('czech')
dispatch('spanish')
Kduyehj
  • 49
  • 1
  • 2
    Could you elaborate more your answer adding a little more description about the solution you provide? – abarisone Mar 26 '15 at 13:30
4

I sometimes use getattr(..) to lazily initialise attributes of secondary importance just before they are used in the code.

Compare the following:

class Graph(object):
    def __init__(self):
        self.n_calls_to_plot = 0

    #...
    #A lot of code here
    #...

    def plot(self):
        self.n_calls_to_plot += 1

To this:

class Graph(object):
    def plot(self):
        self.n_calls_to_plot = 1 + getattr(self, "n_calls_to_plot", 0)

The advantage of the second way is that n_calls_to_plot only appears around the place in the code where it is used. This is good for readability, because (1) you can immediately see what value it starts with when reading how it's used, (2) it doesn't introduce a distraction into the __init__(..) method, which ideally should be about the conceptual state of the class, rather than some utility counter that is only used by one of the function's methods for technical reasons, such as optimisation, and has nothing to do with the meaning of the object.

Evgeni Sergeev
  • 22,495
  • 17
  • 107
  • 124
3

Quite frequently when I am creating an XML file from data stored in a class I would frequently receive errors if the attribute didn't exist or was of type None. In this case, my issue wasn't not knowing what the attribute name was, as stated in your question, but rather was data ever stored in that attribute.

class Pet:
    def __init__(self):
        self.hair = None
        self.color = None

If I used hasattr to do this, it would return True even if the attribute value was of type None and this would cause my ElementTree set command to fail.

hasattr(temp, 'hair')
>>True

If the attribute value was of type None, getattr would also return it which would cause my ElementTree set command to fail.

c = getattr(temp, 'hair')
type(c)
>> NoneType

I use the following method to take care of these cases now:

def getRealAttr(class_obj, class_attr, default = ''):
    temp = getattr(class_obj, class_attr, default)
    if temp is None:
        temp = default
    elif type(temp) != str:
        temp = str(temp)
    return temp

This is when and how I use getattr.

btathalon
  • 185
  • 8
3

Another use of getattr() in implementing a switch statement in Python. It uses both reflection to get the case type.

import sys

class SwitchStatement(object):
    """ a class to implement switch statement and a way to show how to use gettattr in Pythion"""

    def case_1(self):
        return "value for case_1"

    def case_2(self):
        return "value for case_2"

    def case_3(self):
        return "value for case_3"

    def case_4(self):
        return "value for case_4"

    def case_value(self, case_type=1):
        """This is the main dispatchmethod, that uses gettattr"""
        case_method = 'case_' + str(case_type)
        # fetch the relevant method name
        # Get the method from 'self'. Default to a lambda.
        method = getattr(self, case_method, lambda: "Invalid case type")
        # Call the method as we return it
        return method()

def main(_):
    switch = SwitchStatement()
    print swtich.case_value(_)

if __name__ == '__main__':
    main(int(sys.argv[1]))
hoefling
  • 59,418
  • 12
  • 147
  • 194
Jules Damji
  • 179
  • 2
3

setattr()

We use setattr to add an attribute to our class instance. We pass the class instance, the attribute name, and the value.

getattr()

With getattr we retrive these values

For example

Employee = type("Employee", (object,), dict())

employee = Employee()

# Set salary to 1000
setattr(employee,"salary", 1000 )

# Get the Salary
value = getattr(employee, "salary")

print(value)
kuldeep Mishra
  • 228
  • 2
  • 4
2

I think this example is self explanatory. It runs the method of first parameter, whose name is given in the second parameter.

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()
1

It is also clarifying from https://www.programiz.com/python-programming/methods/built-in/getattr

class Person:
    age = 23
    name = "Adam"

person = Person()
print('The age is:', getattr(person, "age"))
print('The age is:', person.age)

The age is: 23

The age is: 23

class Person:
    age = 23
    name = "Adam"

person = Person()

# when default value is provided
print('The sex is:', getattr(person, 'sex', 'Male'))

# when no default value is provided
print('The sex is:', getattr(person, 'sex'))

The sex is: Male

AttributeError: 'Person' object has no attribute 'sex'

Barny
  • 383
  • 1
  • 3
  • 13
0

I have tried in Python2.7.17

Some of the fellow folks already answered. However I have tried to call getattr(obj, 'set_value') and this didn't execute the set_value method, So i changed to getattr(obj, 'set_value')() --> This helps to invoke the same.

Example Code:

Example 1:

    class GETATT_VERIFY():
       name = "siva"
       def __init__(self):
           print "Ok"
       def set_value(self):
           self.value = "myself"
           print "oooh"
    obj = GETATT_VERIFY()
    print getattr(GETATT_VERIFY, 'name')
    getattr(obj, 'set_value')()
    print obj.value
siva balan
  • 389
  • 3
  • 6