在类对象中,如何自动更新属性?

17 投票
4 回答
53435 浏览
提问于 2025-04-17 16:08

我有一个类,这个类里面有多个相关的属性,比如:

class SomeClass:
    def __init__(self, n=0):
        self.list = range(n)
        self.listsquare = [ x**2 for x in self.list ]

如果我正常创建一个对象,那就没问题,像这样:

a = SomeClass(10)

我会得到两个列表,a.lista.listsquare

现在,如果我想先创建一个空对象,然后给它赋一个属性,我希望其他属性也能自动更新。比如,如果我这样做:

b = SomeClass()
b.list = range(5,10)

我希望 b.listsquare 能自动更新,同时反过来也是一样(如果我赋值给 b.listsquare,那么 b.list 也能自动更新)。这样做可以吗?使用 Class 这个方式合适吗?


谢谢大家,但我被各种不同的回答搞得有点晕。有没有人能给我一个完整的解决方案,这样我可以学着自己写?

我想实现一个类 Foo,它有三个属性:lengthlistlistsquare,要求如下:

  1. 如果我写 a = Foo(3),我希望得到 a.length = 3a.list = [0, 1, 2]a.listsquare = [0, 1, 4]
  2. 如果我写 b = Foo().list = [5, 6],我希望得到 b.length = 2b.listsquare = [25, 36]
  3. 如果我写 c = Foo().listsquare = [4, 9],我希望得到 c.length = 2c.list = [2, 3]

4 个回答

5

Ignacio的@property解决方案很不错,但每次你引用listsquare的时候,它都会重新计算这个列表,这样可能会消耗很多资源。Mathew的解决方案也很好,但现在你需要调用函数。其实你可以把这两者结合起来,使用'property'函数。在这里,我为my_list定义了一个获取器和一个设置器(我就是不能叫它'list'!),这样就能生成listsquare:

class SomeClass(object):

    def __init__(self, n=5):
        self.my_list = range(n)

    def get_my_list(self):
        return self._my_list

    def set_my_list(self, val):
        self._my_list = val
        # generate listsquare when my_list is updated
        self.my_listsquare = [x**2 for x in self._my_list]

    # now my_list can be used as a variable
    my_list = property(get_my_list, set_my_list, None, 'this list is squared')

x = SomeClass(3)
print x.my_list, x.my_listsquare
x.my_list = range(10)
print x.my_list, x.my_listsquare

这个输出结果是:

[0, 1, 2] [0, 1, 4]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
8

当然可以。不过建议你使用一个属性

class SomeClass(object):
  def __init__(self, n=5):
    self.mylist = range(n)

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

a = SomeClass()
a.mylist = [4, 5, 8]
print a.listsquare

属性值的缓存留给你自己去练习。

32

如果你想要在更新一个属性的时候,自动更新另一个属性,而不是在访问时重新计算这个属性的值,那你可以使用属性的设置器:

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]

撰写回答