【问题标题】:Why favor object.__setattr__(self, name, value) only in new style classes?为什么只在新样式类中偏爱 object.__setattr__(self, name, value) ?
【发布时间】:2016-12-05 13:23:50
【问题描述】:

根据 Python 2.7.12 文档:

如果__setattr__() 想要分配给一个实例属性,它应该 不仅仅是执行self.name = value——这会导致递归 呼唤自己。相反,它应该在字典中插入值 实例属性,例如,self.__dict__[name] = value为 新型类,而不是访问实例字典,它 应该调用同名的基类方法,例如, object.__setattr__(self, name, value).

但是,以下代码可以正常工作:

class Class(object):
    def __setattr__(self, name, val):
        self.__dict__[name] = val;

c = Class()
c.val = 42
print c.val

我知道super(Class, obj).__setattr__(name, value)可以保证所有基类的__setattr__方法被调用,但是经典类也可以继承自基类。那么为什么只推荐用于新样式类呢?

或者,另一方面,为什么不建议在经典课程中这样做?

【问题讨论】:

  • 那么为什么它只推荐用于新样式类? 调用__setattr__ 而不是直接对实例字典进行操作允许超类对正在发生的事情进行一些“监督”。将此方法视为新样式类的优势。它可能会推荐给所有类,但不继承没有具有可调用__setattr__ 方法的超类的旧式类。
  • @jedwards 是的,因为经典课程没有classobj.__setattr__,新风格课程只有object.__setattr__
  • 你完全正确。我的观点是,我查看了您以粗体表示的句子,而不是直接使用 instance dict 的气馁(正如您所展示的,它在许多情况下都可以正常工作,并且正如 Martijn 所展示的那样,在某些情况下它不会),但更多的是鼓励使用__setattr__,它允许超类一些*监督和使用更新的特性,如描述符。对不起,如果我不清楚:)

标签: python class inheritance setattr new-style-class


【解决方案1】:

新型类可能正在使用 slots,此时没有可分配的 __dict__。新式类还支持其他数据描述符,即在类上定义的对象,用于处理某些名称的属性设置或删除。

来自documentation on slots

默认情况下,旧式和新式类的实例都有一个用于属性存储的字典。这浪费了具有很少实例变量的对象的空间。创建大量实例时,空间消耗会变得非常严重。

可以通过在新样式类定义中定义__slots__ 来覆盖默认值。 __slots__ 声明采用一系列实例变量,并在每个实例中保留足够的空间来保存每个变量的值。节省空间是因为__dict__ 不是为每个实例创建的。

通过在类上添加data descriptors 来实现对插槽的访问;每个此类属性都具有 __set__ 和/或 __del__ 方法的对象。

另一个数据描述符的例子是property() objects,它附加了一个setter或deleter函数。在__dict__ 中设置与此类描述符对象同名的键将被忽略,因为数据描述符会导致属性查找完全绕过__dict__

object.__setattr__() 知道如何处理数据描述符,这就是您应该调用它的原因。

【讨论】:

  • 也许“在__dict__ 中为此类对象设置键将被忽略”应该是“为类使用__dict__ 中的数据描述符的对象设置键将被忽略”到说清楚点?
  • @sunqingyao:有问题的“对象”是类上的数据描述符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2020-08-17
  • 2016-08-17
  • 2011-11-25
  • 2011-12-13
相关资源
最近更新 更多