为什么仅在新样式 类 中支持 object.__setattr__(self, name, value)?

Why favor object.__setattr__(self, name, value) only in new style classes?

根据 Python 2.7.12 文档:

If __setattr__() wants to assign to an instance attribute, it should not simply execute self.name = value — this would cause a recursive call to itself. Instead, it should insert the value in the dictionary of instance attributes, e.g., self.__dict__[name] = value. For new-style classes, rather than accessing the instance dictionary, it should call the base class method with the same name, for example, 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)可以确保调用所有base class的__setattr__方法,但是classic class也可以继承自碱基 classes。那么为什么它只推荐用于新样式 classes?

或者,另一方面,为什么不建议 classic classes 这样做?

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

来自documentation on slots

By default, instances of both old and new-style classes have a dictionary for attribute storage. This wastes space for objects having very few instance variables. The space consumption can become acute when creating large numbers of instances.

The default can be overridden by defining __slots__ in a new-style class definition. The __slots__ declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__ is not created for each instance.

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

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

object.__setattr__() 知道如何处理数据描述符,这就是为什么你应该调用它。