只读或计算成员数据的Getter vs属性



在Python中,成员数据的getter和setter通常不用于属性。原因强调了我们可能希望透明地交换计算和值的情况,以及可能在单个表达式中读取和分配成员的情况。

不能或不能合理分配的成员怎么办?在这种情况下,有没有结构性的理由更喜欢getter或属性?

我想到的具体情况是一个具有可能被缓存的计算成员的类。

这取决于你心目中的特质应该如何被感知。它是一个可以简单访问的属性,还是看起来需要"工作"才能获得?

如果你的特征是一个缓存值,而访问站点不应该影响该特征的检索方式,那么需要表示你正在使用getter函数这一事实意味着你在告诉消费者,有一个过程需要在他们不需要知道的情况下执行。当你故意说他们不需要知道时,为什么要让别人考虑后果?

然而,假设您的getter可能需要访问站点的控制,比如在某些情况下,您可能想要使缓存无效。它可能在使用者代码中不常见,但这由您决定。在这种情况下,您需要一个带参数的getter,或者一个reset方法来处理缓存的属性。

最后一个可能过于夸张的原因是,比起属性,更喜欢方法的原因是属性描述符的访问时间略慢于方法调用,因此,如果在紧密循环中深入访问特性,那么使用属性(甚至是缓存的属性)可能会产生可衡量的影响。

编辑-澄清描述符的成本

检索方法或描述符时,您正在查找名称的值。如果你正在使用一个函数,它只是在查找后调用的。如果您正在使用描述符(@property),则会检测到该描述符,并检索和调用描述符的__get__方法。这意味着描述符有一个额外的查找步骤。这种成本是最低的,对于普通使用来说几乎是不可估量的,但如果它像在内部循环中一样频繁访问,那么价格可能会累积。

In [1]: class Method(object):
   ...:     def get_my_value(self):
   ...:         return 1
   ...:
In [2]: class Property(object):
   ...:     @property
   ...:     def my_value(self):
   ...:         return 1
   ...:
In [3]: M = Method()
In [4]: %timeit M.get_my_value()
The slowest run took 14.74 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 133 ns per loop
In [5]: P = Property()
In [6]: %timeit P.my_value
The slowest run took 8.09 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 181 ns per loop

最新更新