首页 > 解决方案 > 当属性是对象列表时如何识别属性更改

问题描述

矩形对象怎么可能监听点属性 x 和 y,如果它们发生变化,矩形对象会重新计算面积?

如果我使用 setter 和 getter 执行此操作,则每次访问 area 属性时,都会重新计算区域。如果计算非常昂贵(我在这里做了更多的事情),这对我来说不是最佳解决方案。是否可以听点,只有在它们发生变化时才重新计算面积?

我有一个名为 Rectangle 的类和一个名为 Point 的类:

class Point(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y


class Rectangle(object):

    def __init__(self, points=None):
        self.points = [] if points is None else points
        self.area = self.calc_area()

    def calc_area(self):
        return (self.points[0].x - self.points[1].x) * (self.points[0].y - self.points[1].y)

然后我用这两个点创建两个点和一个矩形:

# create the points:
points = list()
points.append(Point(0,0))
points.append(Point(1,1))

# create the rectangle:
rect = Rectangle(points)
print(rect.area)

现在我改变第一个点的坐标:

# change the points coordinates:
points[0].x = 0.5
points[0].y = 0.5

# Now the area should be recalculated.
print(rect.area)

标签: python

解决方案


解决方案:

您可以声明areaproperty

class Rectangle(object):
    def __init__(self, points=list()):
        self.points = points
        # self.area = self.calc_area() -- removed

    @property
    def area(self):
        return = (self.points[0].x - self.points[1].x) * (self.points[0].y - self.points[1].y)

它将解决问题。

更新。

如果您希望仅在值更改时重新计算面积,您可以使用自定义标志并将其设置在属性设置器上。

代码:

class Point(object):
    def __init__(self, x, y):
        self._x = x
        self._y = y
        self.updated = True

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self.updated = True
        self._x = value

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

    @y.setter
    def y(self, value):
        self.updated = True
        self._y = value


class Rectangle(object):
    def __init__(self, points=None):
        self.points = [] if points is None else points
        self._area = 0

    @property
    def area(self):
        if any(point.updated for point in self.points):
            self._area = (self.points[0].x - self.points[1].x) * (self.points[0].y - self.points[1].y)
            for point in self.points:
                point.updated = False
            print("recalculated") # delete it, it's just for test
        return self._area


points = [Point(0, 0), Point(1, 1)]

rect = Rectangle(points)
print(rect.area)
print(rect.area)

points[0].x = 0.5
points[0].y = 0.5

print(rect.area)

输出:

recalculated
1
1
recalculated
0.25

推荐阅读