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

LWZ*_*LWZ 11 python attributes class

我有一个具有多个相关属性的类,例如:

class SomeClass?
    def __init__(self, n=0):
        self.list = range(n)
        self.listsquare = [ x**2 for x in self.list ]
Run Code Online (Sandbox Code Playgroud)

如果我通常做一个没问题的对象,用

a = SomeClass(10)
Run Code Online (Sandbox Code Playgroud)

我将获得2个列表,a.list并且a.listsquare.

现在,如果我想首先创建一个空对象,并为其分配一个属性,我希望其他属性自动更新,例如,如果我这样做

b = SomeClass()
b.list = range(5,10)
Run Code Online (Sandbox Code Playgroud)

我希望b.listsquare自动更新,反之亦然(分配b.listsquare和自动更新b.list).这可能吗?是这个正确的选择?


谢谢大家,但我完全被所有不同的答案所震撼.任何人都可以提供完整的解决方案,这样我就可以自学了吗?

我想实现一类Foo具有3个属性length,list并且listsquare这样的:

  1. 如果我这样做a = Foo(3),我得到的a.length = 3,a.list = [0, 1, 2],a.listsquare = [0, 1, 4].
  2. 如果我这样做b = Foo().list = [5, 6],我会b.length = 2,b.listsquare = [25, 36].
  3. 如果我这样做c = Foo().listsquare = [4, 9],我会c.length = 2,c.list = [2, 3].

Ali*_*fee 17

如果由于对另一个属性的更新而更新一个属性是您正在寻找的(而不是在访问时重新计算下游属性的值)使用属性setter:

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]
Run Code Online (Sandbox Code Playgroud)


Ign*_*ams 6

绝对。但是改用属性

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
Run Code Online (Sandbox Code Playgroud)

属性值的缓存留给读者练习。


tde*_*ney 5

Ignacio 的@property 解决方案很棒,但每次引用 listsquare 时它都会重新计算列表 - 这可能会变得昂贵。Mathew 的解决方案很棒,但现在您有了函数调用。您可以将这些与“属性”功能结合使用。在这里,我为生成 listsquare 的 my_list 定义了一个 getter 和一个 setter(我不能称它为“list”!):

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
Run Code Online (Sandbox Code Playgroud)

这输出:

[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]
Run Code Online (Sandbox Code Playgroud)