【问题标题】:How to use Python properties efficiently?如何有效地使用 Python 属性?
【发布时间】:2018-04-24 06:43:28
【问题描述】:

假设我有一个类Foo 存储一些统计数据,我想使用 Python 属性封装对这些数据的访问。这特别有用,例如,当我只存储变量的方差并希望访问其标准偏差时:在这种情况下,我可以定义属性Foo.std 并使其返回方差的平方根。

这种方式的问题是,如果我需要多次访问Foo.std,每次都要计算平方根;此外,由于属性的符号与属性的符号完全相同,因此我的类的用户可能不知道每次访问属性时都在进行计算。

此示例中的一种替代方法是在每次更新方差时计算标准偏差,并将其设置为属性。但是,如果我不需要在每次更新时都访问它,那将是低效的。

我的问题是:当您需要执行昂贵的计算时,有效使用 Python 属性的最佳方法是什么?我应该在第一次调用后缓存结果并在更新时删除缓存吗?还是我应该不使用属性而改用 Foo.get_std() 方法?

【问题讨论】:

  • "是否应该在第一次调用后缓存结果并在更新时删除缓存?"无论是通过属性还是函数提供,您都应该这样做。
  • 如果您想向用户提示昂贵的程序,我会将它们作为一个函数公开。除非您所做的一切都同样昂贵或如此之快,否则您不在乎。
  • 此外,我不确定您的示例是否是您的真实用例,但是执行完全相同的现有标准(numpy)使用函数来实现这种行为,所以很多人会期望那个。

标签: python properties


【解决方案1】:

通常你可以通过缓存来做到这一点。例如你可以写:

class Foo:

    def __int__(self, also, other, arguments):
        # ...
        self._std = None

    @property
    def std(self):
        if self._std is None:
            # ... calculate standard deviation
            self._std = ...
        return self._std

    def alter_state(self, some, arguments):
        # update state
        self._std = None

所以这里我们有一个属性std,还有一个属性_std。如果尚未计算标准差,或者您更改了对象状态以致标准差可能已更改,我们将_std 设置为None。现在如果我们访问.std,我们首先检查_std 是否为None。如果是这种情况,我们计算标准偏差并将其存储到_std 并返回。这样——如果对象没有改变——我们以后可以简单地检索它。

如果我们更改对象以致标准差可能已更改,我们将_std 设置回None,以强制重新评估以防我们再次访问.std

如果我们在重新计算标准差之前改变Foo 对象的状态两次,我们只会重新计算一次。因此,您可以经常更改Foo 对象,而(接近)不涉及额外成本(将self._std 设置为None 除外)。因此,如果您有一个庞大的数据集并对其进行大量更新,那么您只会在实际需要时再次努力计算标准差。

此外,如果(非常)便宜,这也可以是更新统计指标的机会。例如,假设您有一个经常批量更新的对象列表。如果你用一个常数增加所有元素,那么 mean 也会随着那个常数增加。因此,更改状态以使某些指标也可以轻松更改的函数可能会更新指标,而不是制作这些None

请注意,.std 是属性还是函数无关紧要。用户不必知道必须多久计算一次。 std() 函数将保证一旦计算,第二次检索将非常快。

【讨论】:

    最近更新 更多