[已解决] AttributeError: 不能在python中设置属性
问题的提出
你在代码中创建了一个 [namedtuple](https://blog.finxter.com/the-ultimate-guide-to-python-tuples/#Named_Tuples "https://blog.finxter.com/the-ultimate-guide-to-python-tuples/#Named_Tuples")
对象,你想覆盖其中的一个属性值,就像你对普通对象所习惯的那样。
from collections import namedtuple
Car = namedtuple('Car', 'speed color')
porsche = Car(300, 'gold')
porsche.speed = 400
但是,出乎意料的是,Python 提出了一个 **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
你能做什么? 让我们了解这个错误发生的原因--之后你就会知道最好的解决方法。
为什么会发生这个错误?
任何nametuple
对象也是一个 [tuple](https://blog.finxter.com/the-ultimate-guide-to-python-tuples/ "The Ultimate Guide To Python Tuples")
(子类关系),所以它是不可改变 的--你不能在创建后改变它。例如,如果不创建一个新的元组('Alice', 'Bob')
,你就不能把它改成('Ann', 'Bob')
。
如果你试图改变一个namedtuple
对象的属性值,你就试图修改一个不可变的对象。因此,Python 引发了AttributeError: can't set attribute
。
修复1:使用 namedtuple._replace() 方法
修复AttributeError:can't set attribute
,最简单的方法是用namedtuple
对象创建一个新的 [namedtuple._replace()](https://docs.python.org/3/library/collections.html#collections.somenamedtuple._replace "https://docs.python.org/3/library/collections.html#collections.somenamedtuple._replace")
方法创建一个新的 对象。例如,如果你想把命名元组对象n
的属性x
改为值42
,调用n._replace(x=42)
。结果是一个新的namedtuple
对象,所有的属性都被复制,除了新传递的属性。最后,用新的namedtuple
覆盖原始变量n
。
这里是应用于我们前面例子的修复方法。
from collections import namedtuple
Car = namedtuple('Car', 'speed color')
porsche = Car(300, 'gold')
porsche = porsche._replace(speed=400)
你可以在下面的语句中看到 [print()](https://blog.finxter.com/python-print/ "Python print()")
语句中,speed
的原始属性值已经从300变成了400。
print(porsche)
# Car(speed=300, color='gold')
注意,这通常是低效的,因为所有其他的属性都必须被复制,只是为了更新一个单一的属性!
我们可以解决这个问题吗?当然可以!
修复2。不要使用命名图元而是使用类
Namedtuples 是不可变的对象,所以你不能改变属性值。但是标准的 Python 类是可变的,所以它们可以被任意地改变。具体来说,你_可以_ 改变一个现有属性的值,甚至可以使用 "鸭子类型 "动态地给一个现有对象添加一个新属性。
下面的代码与我们的例子代码完成了同样的事情--但它使用标准的Python类而不是namedtuples
,更有效地完成了这个任务。
class Car:
def __init__(self, speed, color):
self.speed = speed
self.color = color
porsche = Car(300, 'gold')
porsche.speed = 400
让我们确认一下,属性值已经变成了400。
print(porsche.speed)
# 400
你甚至可以像这样给对象添加一个额外的属性,例如price
。
porsche.price = 100000
print(porsche.price)
# 100000
修复方法#3:使用字典
对于轻量级的应用程序,你也可以使用一个简单的字典,而不是命名的图元或类。字典被设计用来保存_键:值_而不是_属性:值_对。例如,你可以创建一个 dictionary{'key_1': 'value_1', 'key_2': 'value_2'}
来存储两个键而不是属性。现在你可以使用dict['key_1'] = 'new_value'
来更新一个键,而不是更新一个属性。
下面是这个解决方案应用于我们之前的问题--发生了相当大的简化
porsche = {'speed': 300, 'color': 'gold'}
porsche['speed'] = 400
让我们检查一下属性是否已经改变。
print(porsche['speed'])
# 400
的确,输出已经改变,而且没有错误信息存在。
修复4:如果你必须使用Namedtuples,使用一个可变的属性
如果你必须使用namedtuples
,并且你需要用一个新的值来更新一个现有的属性,并且由于效率的原因你不能用_replace()
来创建一个新的属性,你可以做以下的事情。
将nametuple
对象的属性创建为可改变的对象,如列表。你总是可以改变一个列表的内容,因为它是可变的。因此,从语义上讲,你修改namedtuple
属性的值,实际上并没有违反不变性标准--namedtuple
仍然指向内存中的同一个可变对象(例如,列表)。
下面是这个应用于例子问题的解决方案。
from collections import namedtuple
Car = namedtuple('Car', 'speed color')
porsche = Car([300], 'gold')
porsche.speed[0] = 400
虽然你可能不会觉得这个解决方案特别性感,但它却像一个魅力。
print(porsche.speed)
# [400]
速度的原始值已经改变,而且没有发生错误。
从哪里开始?
理论够多了,让我们去实践一下吧!
要想在编码方面取得成功,你需要走出去,为真正的人解决真正的问题。这样你才能轻松成为六位数的收入者。而这也是你如何在实践中打磨出你真正需要的技能。毕竟,学习没有人需要的理论有什么用?
实践项目就是你在编码中磨练你的锯子的方法!
你想通过专注于实际的代码项目,成为一个代码大师,真正为你挣钱,为人们解决问题吗?
那就成为Python的自由开发者吧!这是接近提高Python技能任务的最好方式--即使你是一个完全的初学者。
参加我的免费网络研讨会"如何建立你的高收入技能Python",看看我是如何在网上发展我的编码业务的,你也可以这样做--从你自己家里的舒适度。
The post[Solved] AttributeError: can't set attribute in pythonfirst appeared onFinxter.
转载自:https://juejin.cn/post/7090078574488584228