paper.cut
paper.cut

Reputation: 285

What's the difference between setattr() and object.__setattr__()?

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

Answers (2)

Aray Karjauv
Aray Karjauv

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):

  1. Normal attribute setting: setattr() is the function equivalent of the assignment operation. It's like doing my_obj.name = value.

  2. Respects the class hierarchy: It will call the __setattr__() method of the object's class, which may be overridden in subclasses.

  3. Triggers descriptors: If the attribute is a descriptor, setattr() will trigger its __set__() method.

Upvotes: -1

Ethan Furman
Ethan Furman

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.


Original Answer*

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
  • etc

Upvotes: 18

Related Questions