Reputation: 285
I know that you can't call object.__setattr__
on objects not inherited from object
, but is there anything else that is different between the two? I'm working in Python 2.6, if this matters.
Upvotes: 23
Views: 14360
Reputation: 2945
While both setattr
(also the assignment operator =
) and object.__setattr__
behave differently and are used in different contexts, the Python documentation doesn't explicitly state it. object.__setattr__
directly sets the attribute of a class instance, bypassing any custom __setattr__
methods defined in the class hierarchy.
class A:
def __init__(self):
self.a = 0
def __setattr__(self, name, value):
self.__dict__[name] = value**2
a = A()
print(a.a) # => 0
a.a = 2
print(a.a) # => 4
setattr(a, 'a', 3)
print(a.a) # => 9
object.__setattr__(a, 'a', 4)
print(a.a) # => 4
To summarize, setattr(object, name, value)
:
Normal attribute setting: setattr()
is the function equivalent of the assignment operation. It's like doing my_obj.name = value
.
Respects the class hierarchy: It will call the __setattr__()
method of the object's class, which may be overridden in subclasses.
Triggers descriptors: If the attribute is a descriptor, setattr()
will trigger its __set__()
method.
Upvotes: -1
Reputation: 69041
Reading this question again I misunderstood what @paper.cut was asking about: the difference between classic classes and new-style classes (not an issue in Python 3+). I do not know the answer to that.
setattr(instance, name, value)
is syntactic sugar for instance.__setattr__(name, value)
**.
You would only need to call object.__setattr__(...)
inside a class definition, and then only if directly subclassing object
-- if you were subclassing something else, Spam
for example, then you should either use super()
to get the next item in the heirarchy, or call Spam.__setattr__(...)
-- this way you don't risk missing behavior that super-classes have defined by skipping over them directly to object
.
* applies to Python 3.0+ classes and 2.x new-style classes
**There are two instances where setattr(x, ...)
and x.__setattr__(...)
are not the same:
x
itself has a __setattr__
in it's private dictionary (so x.__dict__[__setattr__] = ...
(this is almost certainly an error)
x.__class__
has a __getattribute__
method -- because __getattribute__
intercepts every lookup, even when the method/attribute exists
NB These two caveats apply to every syntactic sugar shortcut:
setattr
getattr
len
bool
hash
Upvotes: 18