Why use setattr() and getattr() built-ins?

Question:

From reading the docs, I understand exactly what getattr() and setattr() do. But it also says explicitly that getattr(x, 'foobar') is equivalent to x.foobar and setattr(x, 'foobar', 123) is equivalent to x.foobar = 123.

So why would I use them?

Answers:

Because you can use a dynamic variable too:

somevar = 'foo'
getattr(x, somevar)

You can’t do that with regular attribute access syntax.

Note that getattr() also takes an optional default value, to be returned if the attribute is missing:

>>> x = object()
>>> getattr(x, 'foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'foo'
>>> getattr(x, 'foo', 42)
42

Using getattr() you can pull the attribute name from something else, not a literal:

for attrname in dir(x):
    print('x.{} = {!r}'.format(attrname, getattr(x, attrname))

or you can use setattr() to set dynamic attributes:

for i, value in enumerate(dynamic_values):
    setattr(i, 'attribute{}'.format(i), value)
Answered By: Martijn Pieters

You use them if the attribute you want to access is a variable and not a literal string. They let you parameterize attribute access/setting.

There’s no reason to do getattr(x, 'foobar'), but you might have a variable called attr that could be set to “foobar” or “otherAttr”, and then do getattr(x, attr).

Answered By: BrenBarn

I find it most useful when there is a possibility that the object whose attribute you need might be None. Exemplified below;

obj = None
attr_val = getattr(obj, 'anyvar', None) #This is not an error.
Answered By: Abraham Imohiosen

Another case probably shows that they are not totally identical:

class A:
    def __init__(self):
        self.__var = 10
        setattr(self, '__var2', 100)

a = A()
print(a.__var2)
# 100
print(a.__var)
# AttributeError: 'A' object has no attribute '__var'

At least, setattr is not identical to ..

Answered By: Hou Lu

There is a difference between setattr and ., not documented yet:

class X:

    def __init__(self, value1, value2):
        self.__non_private_name_1 = value1
        setattr(self, '__non_private_name_2', value2)


>>> x = X('Hi', 'Bye')
>>> x.__dict__
{'_X__non_private_name_1': 'Hi', '__non_private_name_2': 'Bye'}

The latter one, when used to set a dunder value (ones with double underscores) adds a single underscore _ + self.__class__.__name__(i.e. X) to the beginning of the string in right side of . and sets the attribute named with the resulting string(i.e. _X__non_private_name_1).

Answered By: S.Khajeh
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.