在类对象中,如何仅更改列表中的一个条目时自动更新属性?

时间:2016-09-29 15:56:25

标签: python class attributes

我在一个非常相似的问题上看到了这个答案:

In class object, how to auto update attributes?

我会在此处粘贴代码:

class SomeClass(object):
    def __init__(self, n):
        self.list = range(0, n)

    @property
    def list(self):
        return self._list
    @list.setter
    def list(self, val):
        self._list = val
        self._listsquare = [x**2 for x in self._list ]

    @property
    def listsquare(self):
        return self._listsquare
    @listsquare.setter
    def listsquare(self, val):
        self.list = [int(pow(x, 0.5)) for x in val]

>>> c = SomeClass(5)
>>> c.listsquare
[0, 1, 4, 9, 16]
>>> c.list
[0, 1, 2, 3, 4]
>>> c.list = range(0,6)
>>> c.list
[0, 1, 2, 3, 4, 5]
>>> c.listsquare
[0, 1, 4, 9, 16, 25]
>>> c.listsquare = [x**2 for x in range(0,10)]
>>> c.list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

在此代码中,当我使用:

更新列表时
>>> c.list = [1, 2, 3, 4]

c.listsquare将相应更新:

>>> c.listsquare
[1, 4, 9, 16]

但是当我尝试时:

>>> c.list[0] = 5
>>> c.list
[5, 2, 3, 4]

Listsquares未更新:

>>> c.listsquare
[1, 4, 9, 16]

当我只更改列表中的一个项目时,如何才能使listsquare自动更新?

2 个答案:

答案 0 :(得分:1)

你可以做的一种方法是拥有一个私有助手_List类,它几乎与内置的list类完全相同,但也有owner属性。每次为_List个实例的元素之一分配一个值时,它就可以修改其listsquare的{​​{1}}属性以使其保持最新状态。由于它仅由owner使用,因此它可以嵌套在其中以提供更多的封装。

SomeClass

答案 1 :(得分:1)

首先,我建议您不要通过访问单个list.setter来更改两个不同的属性。原因是:

>>> c.list[0] = 5
>>> c.list
[5, 2, 3, 4]
>>> c.listsquare
[1, 4, 9, 16]

不起作用,就是说,你正在访问c.list .__ setitem__方法。

c.list[0] = 5 
is equal to
c.list.__setitem__(0, 5)
or
list.__setitem__(c.list, 0, 5)
and as such, the list.__setitem__ method isn't the one you've implemented in your class.

但是,如果你真的想这样做,你应该重新考虑根据self._list创建方形列表。

class SomeClass(object):
    def __init__(self, n):
        self.list = range(0, n)

    @property
    def list(self):
        return self._list

    @list.setter
    def list(self, val):
        self._list = val

    @property
    def listsquare(self):
        return [n ** 2 for n in self.list]

    @listsquare.setter
    def listsquare(self, val):
        self.list = [int(pow(x, 0.5)) for x in val]