AttributeError: can't set attribute in python

PythonAttributes

Python Problem Overview


Here is my code

N = namedtuple("N", ['ind', 'set', 'v'])
def solve()
    items=[]
    stack=[]
    R = set(range(0,8))
    for i in range(0,8):
        items.append(N(i,R,8))		
        stack.append(N(0,R-set(range(0,1)),i))
    while(len(stack)>0): 
        node = stack.pop()
        print node
        print items[node.ind]	
        items[node.ind].v = node.v

In the last line I cant set the items[node.ind].v value to node.v as I want, and am getting the error

"AttributeError: can't set attribute"

I don't know what's wrong but it must be something based on syntax as using statements like node.v+=1 is also showing same error. I'm new to Python, so please suggest a way to make the above change possible.

Python Solutions


Solution 1 - Python

items[node.ind] = items[node.ind]._replace(v=node.v)

(Note: Don't be discouraged to use this solution because of the leading underscore in the function _replace. Specifically for namedtuple some functions have leading underscore which is not for indicating they are meant to be "private")

Solution 2 - Python

namedtuples are immutable, just like standard tuples. You have two choices:

  1. Use a different data structure, e.g. a class (or just a dictionary); or
  2. Instead of updating the structure, replace it.

The former would look like:

class N(object):

    def __init__(self, ind, set, v):
        self.ind = ind
        self.set = set
        self.v = v

And the latter:

item = items[node.ind]
items[node.ind] = N(item.ind, item.set, node.v)

Edit: if you want the latter, Ignacio's answer does the same thing more neatly using baked-in functionality.

Solution 3 - Python

For those searching this error, another thing that can trigger AtributeError: can't set attribute is if you try to set a decorated @property that has no setter method. Not the problem in the OP's question, but I'm putting it here to help any searching for the error message directly. (if you don't like it, go edit the question's title :)

class Test:
    def __init__(self):
        self._attr = "original value"
        # This will trigger an error...
        self.attr = "new value"
    @property
    def attr(self):
        return self._attr

Test()

Solution 4 - Python

This error can be triggered if you try to redefine a member variable that is already defined in the class you inherited.

from pytorch_lightning import LightningModule

class Seq2SeqModel(LightningModule):
    def __init__(self, tokenizer, bart, hparams):
        super().__init__()
        self.tokenizer = tokenizer
        self.bart: BartForConditionalGeneration = bart
        self.hparams = hparams  # This triggers the error
        # Changing above line to below removes the error
        # self.hp = hparams

As I was new to PyTorch and PyTorch Lightning, I did not know the LightningModule already had a member variable named self.hparams. As I tried to overwrite it in my code, it caused AttributeError: can't set attribute.

Just simply renaming my variable from self.hparams to something else removed the error.

Not the problem in the OP's question, but I'm putting it here to help any searching for the error message directly

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPratyush DhanukaView Question on Stackoverflow
Solution 1 - PythonIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 2 - PythonjonrsharpeView Answer on Stackoverflow
Solution 3 - PythonAzmisovView Answer on Stackoverflow
Solution 4 - PythonMatt YoonView Answer on Stackoverflow