【问题标题】:In class object, how to auto update attributes?在类对象中,如何自动更新属性?
【发布时间】:2013-02-01 16:50:56
【问题描述】:

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

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

如果我正常地制作一个没有问题的对象,用

a = SomeClass(10)

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

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

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

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


谢谢大家,但我完全被所有不同的答案弄得不知所措。任何人都可以提供一个完整的解决方案,以便我可以自己学习编写吗?

我想实现一个具有 3 个属性 lengthlistlistsquare 的类 Foo,这样:

  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]

【问题讨论】:

  • 您给我们的代码不起作用。类由 'class' 而不是 'def' 定义,并通过 'def __init__(self, ...)' 方法初始化。您已经定义了一个函数,其中包含 1 个称为“self”的必需参数和 1 个称为“n”的可选参数。当您调用 SomeClass(10) 时,该函数尝试将“列表”分配给 10 对象并失败。 - 哦,看起来问题正在重新格式化......所以没关系。
  • 抱歉,我进行了更正。我现在对它不是很熟悉。

标签: python class attributes


【解决方案1】:

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

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]

【讨论】:

  • 这是否意味着我需要定义 3 个属性(sizelistlistsquare),所以当我更新其中一个属性时,另外两个也会更新?
  • 这是正确的。我已经更新了上面的答案,以按照您想要的方式工作 - size 属性不再需要了。
【解决方案2】:

当然。但请改用属性

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

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

【讨论】:

  • 太棒了!反过来呢?我可以定义a.listsquare 并得到a.mylist 吗?
  • 是的。只需向您的属性添加一个 setter。
【解决方案3】:

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

这个输出:

[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]

【讨论】:

  • 感谢那些指出我初始化列表不正确的人。
【解决方案4】:

您也可以只使用 setter 方法,如下所示:

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

    def set_list(self, n):
        self.list = n
        self.listsquare = [ x**2 for x in self.list ]

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 2021-08-13
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    相关资源
    最近更新 更多