Understanding Python’s setattr() and getattr() Functions
Next, you’ll learn about the “normal”, non-nested and non-recursive get and set attribute functions. If you already know them well, there’s no need to read this section and you can skip ahead right to the problem formulation and solution.
Let’s start with the setattr()
function, followed by getattr()
.
setattr()

Python’s built-in setattr(object, string, value)
function takes three arguments:
- an object,
- a string, and
- an arbitrary value.
It sets the attribute given by the string on the object to the specified value.
After calling the function, there’s a new or updated attribute at the given instance, named and valued as provided in the arguments.
For example, setattr(object, 'attribute', 42)
is equivalent to object.attribute = 42
.
🌍 Recommended Tutorial: Python setattr()
Built-in Function
getattr()

Python’s built-in getattr(object, string)
function returns the value of the object
‘s attribute with name string
.
If this doesn’t exist, it returns the value provided as an optional third default
argument.
If that doesn’t exist either, it raises an AttributeError
.
An example is getattr(porsche, 'speed')
which is equivalent to porsche.speed
.
🌍 Recommended Tutorial: Python getattr()
Built-in Function
Problem Formulation
Consider the following example that creates four classes Family
, Mom
, Dad
, and Kid
. The class Family
points to the other three nested classes (as attributes). The highlighted lines show how you try to set the attribute of a nested class within the Family
class fam
using the setattr()
function.
class Family(object): def __init__(self): self.mom = Mom() self.dad = Dad() self.kid = Kid('Ann') class Mom(object): def __init__(self, name='Jane'): self.name = 'Jane' class Dad(object): def __init__(self, name='Jane'): self.name = 'John' class Kid(object): def __init__(self, name): self.name = name fam = Family() setattr(fam, 'mom.age', 33) setattr(fam, 'kid.sport', 'soccer') print(fam.__dict__)
So, you try to create an attribute age and an attribute sport for the first kid. However, it doesn’t work—Python simply creates a weirdly-named attribute mom.age
and kid.sport
on the Family
class.
{'mom': <__main__.Mom object at 0x0000020BB73BE9A0>, 'dad': <__main__.Dad object at 0x0000020BB73BE910>, 'kids': [<__main__.Kid object at 0x0000020BB73BE040>, <__main__.Kid object at 0x0000020BB73BE1C0>], 'mom.age': 33, 'kid.sport': 'soccer'}
Solution
We use the excellent solution by unutbu that creates two recursive functions rsetattr()
and rgetattr()
that essentially call themselves recursively to obtain the desired outcome of setting attributes of nested classes.
See the highlighted lines:
import functools def rsetattr(obj, attr, val): pre, _, post = attr.rpartition('.') return setattr(rgetattr(obj, pre) if pre else obj, post, val) def rgetattr(obj, attr, *args): def _getattr(obj, attr): return getattr(obj, attr, *args) return functools.reduce(_getattr, [obj] + attr.split('.')) ##### class Family(object): def __init__(self): self.mom = Mom() self.dad = Dad() self.kid = Kid('Ann') class Mom(object): def __init__(self, name='Jane'): self.name = 'Jane' class Dad(object): def __init__(self, name='Jane'): self.name = 'John' class Kid(object): def __init__(self, name): self.name = name fam = Family() rsetattr(fam, 'mom.age', 33) rsetattr(fam, 'kid.sport', 'soccer') print(fam.__dict__) # {'mom': <__main__.Mom object at 0x000002601DE408E0>, 'dad': <__main__.Dad object at 0x000002601DE40190>, 'kid': <__main__.Kid object at 0x000002601DE40250>} print(fam.mom.age) # 33 print(fam.kid.sport) # soccer
Note that the second part of the code after the definition of the rgetattr()
and rsetattr()
functions remains pretty much unchanged.
Unlike the previous example, however, using 'mom.age'
and 'kid.sport'
as name arguments of rsetattr()
actually do set an attribute at a nested subclass mom
or kid
, instead of a flat attribute named 'mom.age'
or 'kid.sport'
with the dot character '.'
as part of the attribute name.
You can see that the recursion even goes deeper than that — if you need it to go that far:
rsetattr(fam, 'mom.fam', Family()) rsetattr(fam, 'mom.fam.mom.car', 'porsche') print(fam.mom.fam.mom.car) # porsche
Where to Go From Here?
Thanks for reading this tutorial and for taking time out of your day to learn with Finxter.
If you want to keep improving your skills, feel free to join our free email academy and download our Python cheat sheets — they are free!

While working as a researcher in distributed systems, Dr. Christian Mayer found his love for teaching computer science students.
To help students reach higher levels of Python success, he founded the programming education website Finxter.com that has taught exponential skills to millions of coders worldwide. He’s the author of the best-selling programming books Python One-Liners (NoStarch 2020), The Art of Clean Code (NoStarch 2022), and The Book of Dash (NoStarch 2022). Chris also coauthored the Coffee Break Python series of self-published books. He’s a computer science enthusiast, freelancer, and owner of one of the top 10 largest Python blogs worldwide.
His passions are writing, reading, and coding. But his greatest passion is to serve aspiring coders through Finxter and help them to boost their skills. You can join his free email academy here.