temporary_user_name
temporary_user_name

Reputation: 37108

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

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?

Upvotes: 55

Views: 12764

Answers (7)

Anthony Labarre
Anthony Labarre

Reputation: 2804

I ran into another use case that requires the use of setattr: decorating imported recursive functions. If you implement the recursive computation of the Fibonacci numbers in a file fibo.py:

def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)

and you then want to take advantage of lru_cache in main.py when you import that function, then the straightforward way that works within fibo.py does not work in main.py:

from fibo import fib
from functools import lru_cache
fib = lru_cache(fib)
print(fib(42))  # takes ages

The setattr way works however:

import fibo
from functools import lru_cache
setattr(fibo, "fib", lru_cache(fibo.fib))
print(fibo.fib(42))  # lightning fast

EDIT: well, it turns out that the straightforward way works too if you import the whole module:

import fibo
from functools import lru_cache
fibo.fib = lru_cache(fibo.fib)
print(fibo.fib(42))  # lightning fast

Upvotes: 0

user20432160
user20432160

Reputation: 11

i think python has deep thinking to support setattr() and getattr() on instance.

Imaging that you have an instance like a baby, who knows nothing when it is born. i.e. there is no any attributes in that instance. As long as the baby grows up, he/she learns more and more skills, so that setattr() is used to make it work, and it makes no one identical even if all the baby instances are created from the same class.

Upvotes: -1

S.Khajeh
S.Khajeh

Reputation: 359

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).

Upvotes: 2

Hou Lu
Hou Lu

Reputation: 3232

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 ..

Upvotes: 7

Abraham Imohiosen
Abraham Imohiosen

Reputation: 31

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.

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1124548

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)

Upvotes: 74

BrenBarn
BrenBarn

Reputation: 251568

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).

Upvotes: 14

Related Questions