关于python:复合赋值的属性设置器?

Property setters for compound assignment?

考虑下面的简单示例类,该类的属性在调用时公开一些内部数据的修改版本:

1
2
3
4
5
6
7
8
9
10
11
12
class Foo(object):
    def __init__(self, value, offset=0):
        self._value = value
        self.offset = offset

    @property
    def value(self):
        return self._value + self.offset

    @value.setter
    def value(self, value):
        self._value = value

value.setter对于常规任务来说是很好的,但是对于复合任务来说当然是坏的:

1
2
3
4
5
6
7
8
9
>>> x = Foo(3, 2)
>>> x.value
5
>>> x.value = 2
>>> x.value
4
>>> x.value += 5
>>> x.value
11

所期望的行为是,与x.value = x.value + 5相反,x.value += 5应等同于x.value = x._value + 5。是否有任何方法可以(通过属性接口)完全在Foo类中实现这一点?


@Ezod,即使使用描述符协议,也没有直接的方法来做你想要做的事情。这种value属性的行为完全破坏了+=操作符的语义。


重写__iadd__magic方法。

您需要这样做,因为+=意味着"取值并加5,然后将其设置为结果"。如果您想让它知道值不是真正的值,您需要更改+=运算符的语义。


我也遇到了同样的问题,用以下方法解决了它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Foo(object):
    def __init__(self):
        self._y = 0

    @property
    def y(self):
        return self._y + 5

    @y.setter
    def y(self, value):
        value -= 5
        self._y = value


>>> f = Foo()
>>> f.y
5
>>> f.y += 1
>>> f._y
1
>>> f.y
6

这是一个解决方案吗?我忽略了什么吗?


The desired behavior is that x.value += 5 should be equivalent to
x.value = x._value + 5

为什么python应该知道属性是如何实现的(即,setter将其值精确地分配给_x

property的协议允许您为一个名称分配不同的操作(get、set、delete)。这个协议并不关心这些行为的实现方式。

所以,如果Python对您的代码做一些假设,并尝试修改Straight Forward代码逻辑,那将是非常容易混淆的。