Problem Formulation
You create a namedtuple
object in your code and you want to overwrite one of the attribute values like you’re used to for normal objects:
from collections import namedtuple Car = namedtuple('Car', 'speed color') porsche = Car(300, 'gold') porsche.speed = 400
But, unexpectedly, Python raises an AttributeError: can't set attribute
. ?
Traceback (most recent call last): File "C:\Users\xcent\Desktop\code.py", line 5, in <module> porsche.speed = 400 AttributeError: can't set attribute
What can you do? ? Let’s understand the reason this error occurs—after that, you’ll learn the best fixes.
Why Does This Error Occur?
Any namedtuple
object is also a tuple
(subclass relationship), so it is immutable — you cannot change it after creation.
For example, you cannot change a tuple ('Alice', 'Bob')
to ('Ann', 'Bob')
without creating a new one.
If you attempt to change a namedtuple
object’s attribute value, you try to modify an immutable object. Consequently, Python raises the AttributeError: can't set attribute
.
Fix #1: Use the namedtuple._replace() Method
The easiest way to fix the AttributeError:can't set attribute
is to create a new namedtuple
object with the namedtuple._replace()
method. The result is a new namedtuple
object with all attributes copied except the newly passed one.
For example, if you want to change attribute x
of named tuple object n
to the value 42
, call n._replace(x=42)
.
Here’s the fix applied to our previous example:
from collections import namedtuple Car = namedtuple('Car', 'speed color') porsche = Car(300, 'gold') porsche = porsche._replace(speed=400)
You can see in the following print()
statement that the original attribute value for speed
has changed from 300 to 400.
print(porsche) # Car(speed=300, color='gold')
Note that this is generally inefficient because all other attributes have to be copied just to update a single attribute!
Can we resolve this? Sure!
Fix #2: Don’t Use Namedtuples But Classes
Namedtuples are immutable objects, so you cannot change the attribute values. But standard Python classes are mutable, so they can be changed arbitrarily. Specifically, you can change an existing attribute’s value and even dynamically add a new attribute to an existing object.
The following code accomplishes the same thing as our example code—but it does so more effectively using standard Python classes rather than namedtuples
:
class Car: def __init__(self, speed, color): self.speed = speed self.color = color porsche = Car(300, 'gold') porsche.speed = 400
Let’s confirm that the attribute value has changed to 400:
print(porsche.speed) # 400
You can even add an additional attribute, say price
, to the object like so:
porsche.price = 100000 print(porsche.price) # 100000
Fix #3: Use Dictionaries
For lightweight applications, you can also use a simple dictionary instead of namedtuples or classes. Dictionaries are designed to hold key: value instead of attribute: value pairs. For instance, you can create a dictionary {'key_1': 'value_1', 'key_2': 'value_2'}
to store two keys instead of attributes. Instead of updating an attribute, you’d now update a key using dict['key_1'] = 'new_value'
.
Here’s this solution applied to our previous problem—quite some simplification has happened!
porsche = {'speed': 300, 'color': 'gold'} porsche['speed'] = 400
Let’s check if the attribute has changed:
print(porsche['speed']) # 400
Indeed, the output has changed and no error message exists.
Fix #4: If You Must Use Namedtuples, Use A Mutable Attribute
If you must use namedtuples
— for example to update an existing attribute with a new value — and you cannot create a new one with _replace()
for efficiency reasons, do the following:
Create the nametuple
object’s attributes as mutable objects such as lists. You can always change the contents of a list because it is mutable. So, semantically, you modify the value of a namedtuple
attribute without actually violating the immutability criterion—the namedtuple
still points to the same mutable object (e.g., a list) in memory.
Here’s this solution applied to the example problem:
from collections import namedtuple Car = namedtuple('Car', 'speed color') porsche = Car([300], 'gold') porsche.speed[0] = 400
Although you may not find this solution particularly sexy, it works like a charm:
print(porsche.speed) # [400]
The original value for speed has changed and no error occurred.
Where to Go From Here?
Enough theory. Let’s get some practice!
Coders get paid six figures and more because they can solve problems more effectively using machine intelligence and automation.
To become more successful in coding, solve more real problems for real people. That’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?
You build high-value coding skills by working on practical coding projects!
Do you want to stop learning with toy projects and focus on practical code projects that earn you money and solve real problems for people?
🚀 If your answer is YES!, consider becoming a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.
If you just want to learn about the freelancing opportunity, feel free to watch my free webinar “How to Build Your High-Income Skill Python” and learn how I grew my coding business online and how you can, too—from the comfort of your own home.