Reputation: 37108
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
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
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
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
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
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
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
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