如何有效地使用Python属性?

时间:2017-11-10 23:57:05

标签: python properties

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

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

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

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

1 个答案:

答案 0 :(得分:7)

通常您可以通过缓存来完成此操作。例如,你可以写:

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()函数将保证一旦计算,第二次检索将非常快。