AttributeError:无法设置属性

111 投票
7 回答
279419 浏览
提问于 2025-04-17 23:18

这是我的代码

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

在最后一行,我无法把 items[node.ind].v 的值设置为 node.v,我想这样做,但却出现了错误

"AttributeError: can't set attribute"

我不知道哪里出问题了,但这肯定是语法方面的原因,因为像 node.v+=1 这样的语句也显示了同样的错误。我是Python的新手,所以请给我一些建议,让我能实现上面的修改。

7 个回答

1

我在错误地把数据类和命名元组混在一起时遇到了这个问题。把它发在这里,希望能帮到某些人,免得他们抓狂。

@dataclasses.dataclass
class Foo(typing.NamedTuple):
    bar: str
3

这个错误会在你尝试重新定义一个已经在你继承的类中定义的成员变量时出现。

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

因为我刚接触PyTorchPyTorch Lightning,所以不知道LightningModule已经有一个叫self.hparams的成员变量。当我在代码中试图覆盖它时,就出现了AttributeError: can't set attribute的错误。

只需把我的变量名从self.hparams改成其他名字,就解决了这个错误。

这不是原问题的答案,但我把它放在这里,以帮助那些直接搜索这个错误信息的人。

75

namedtuple 是不可变的,就像普通的元组一样。你有两个选择:

  1. 使用不同的数据结构,比如一个类(或者直接用字典);或者
  2. 不更新这个结构,而是替换掉它。

第一个选择看起来像这样:

class N(object):

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

而第二个选择则是:

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

如果你想要第二个选择,Ignacio的回答用内置功能做得更简洁。

141

对于那些在寻找这个错误的人,还有一种情况也会导致 AtributeError: can't set attribute 这个错误,那就是你试图设置一个没有设置方法的装饰器 @property。这不是原问题中的情况,但我把它放在这里是为了帮助那些直接搜索这个错误信息的人。如果你不喜欢这个解释,可以去编辑问题的标题 :)

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()
85
items[node.ind] = items[node.ind]._replace(v=node.v)

(注意:不要因为函数名开头有个下划线就对这个解决方案感到沮丧。特别是对于命名元组(namedtuple),有些函数前面有下划线并不是表示它们是“私有”的意思。)

撰写回答