According to Python 2.7.12 documentation:
If
__setattr__()
wants to assign to an instance attribute, it should not simply executeself.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)
.
However, the following code works as one would expect:
class Class(object):
def __setattr__(self, name, val):
self.__dict__[name] = val;
c = Class()
c.val = 42
print c.val
I know super(Class, obj).__setattr__(name, value)
can ensure the __setattr__
methods of all base classes to be called, but classic class can also inherit from bases classes. So why is it only recommended for new style classes?
Or, on the other hand, why is doing so not recommended for classic classes?
New-style classes could be using slots, at which point there is no __dict__
to assign to. New-style classes also support other data descriptors, objects defined on the class that handle attribute setting or deletion for certain names.
From the 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.
Access to slots is instead implemented by adding data descriptors on the class; an object with __set__
and / or __del__
methods for each such attribute.
Another example of data descriptors are property()
objects that have a setter or deleter function attached. Setting a key with the same name as such a descriptor object in the __dict__
would be ignored as data descriptors cause attribute lookup to bypass the __dict__
altogether.
object.__setattr__()
knows how to handle data descriptors, which is why you should just call that.