我想知道如何在修改对象而不是为其分配对象时使@property装饰器调用构造函数。
class Celsius:
def __init__(self, temperature = [0]):
self._temperature = temperature
@property
def temperature(self):
print("Getting value")
return self._temperature
@temperature.setter
def temperature(self, value):
print('setting temperature')
self._temperature = value
a=Celsius()
a.temperature
Getting value
Out[10]: [0]
a.temperature = 7
setting temperature
a.temperature = [7,8]
setting temperature
a.temperature[0] = 0
Getting value
a.temperature
Getting value
Out[14]: [0, 8]
如您所见,如果分配温度,则属性会被调用,而如果列表被修改,它不会调用构造函数,而是会调用“显示器”
我知道@property可能无法完成此操作,但这是我找到的最接近的主意。
实际上,它如何改变温度和_temperature的值?
答案 0 :(得分:0)
设置值时看到“获取值”输出的原因是因为您正在修改_temperature变量。
要修改变量,必须首先对其进行检索。覆盖变量时,不需要首先检索它,而只需对其进行设置即可。
之所以看不到“设置温度”输出,是因为您实际上是在修改_temperature的基础对象(一个列表),所以不使用属性设置器。
答案 1 :(得分:0)
顺序:
>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature
>>> a.temperature[0] = 0
getting value
特别有趣,因为您授予了_temperature
列表的访问权限,并且邪恶的用户可能破坏您的Celsius
实例。一个人想要这样的东西:
>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.temperature[0] = 0
setting ONE temperature (I CHECK THAT THIS VALUE IS CONSISTENT)
基本上,您无法控制对象,因为您无法检查邪恶用户可以做什么。这似乎是一个危险的设计。这是一个建议:永远不要与外部世界共享一个可变的对象,始终提供一个不变的对象或副本。(这可以确保遵守Law of Demeter)。替换:
@property
def temperature(self):
print("getting value")
return self._temperature
通过:
@property
def temperature(self):
print("getting value")
return list(self._temperature)
并尝试您的测试用例:
>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.temperature[0] = 0
getting value
>>> a.temperature
getting value
[7, 8] # NO MODIFICATION HERE
现在,您的Celsius
对象受到了保护,不能进行野蛮的修改:如果要更改_temperature
列表,则必须提供一个完整的列表,设置者应检查该列表。
如果要更改单个值,仍然可以,但是可以调用设置器(并可能进行检查):
>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> new_temp = [0] + a.temperature[1:]
getting value
>>> a.temperature = new_temp
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.temperature
getting value
[0, 8]
如果您绝对希望用户按索引设置项目,则必须手动编写函数:
class Celsius:
...
def set_temperature_item(self, i, v):
print ("setting ONE temperature (I CHECK THAT THIS VALUE IS CONSISTENT)")
self._temperature[i] = v
>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.set_temperature_item(0, 0)
setting ONE temperature (I CHECK THAT THIS VALUE IS CONSISTENT)
>>> a.temperature
getting value
[0, 8]
我认为您不能使用property
来完成此操作,因为在您写时:
a.temperature[0] = 0
等效于:
a.__getattribute__("temperature").__setitem__(0, 0)
您无法确定__getattribute__
调用下一步将发生什么:仅获取值或使用它来设置项目。