[Solved] AttributeError: can’t set attribute in python

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 nametuple 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 an attribute value of a namedtuple object, 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. For example, if you want to change attribute x of named tuple object n to the value 42, call n._replace(x=42). The result is a new namedtuple object with all attributes copied except the newly passed one. Finally, overwrite the original variable n with the new namedtuple.

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 it 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 and you need to update an existing attribute with a new value and you cannot create a new one with _replace() for efficiency reasons, you can 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!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And 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?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

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

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!