Skip to content
Advertisement

Why isn’t setattr(super(), …) equivalent to super().__setattr__(…)?

According to this answer:

setattr(instance, name, value) is syntactic sugar for instance.__setattr__(name, value)

But:

class C:
    def __init__(self):
        # OK.
        super().__setattr__("foo", 123)

        # AttributeError: 'super' object has no attribute 'foo'
        setattr(super(), "foo", 123)

c = C()

What gives? Shouldn’t they both do the same thing?

Advertisement

Answer

The answer you linked to glosses over some important details. Long story short, setattr bypasses super‘s magic, so it tries to set attributes on the super() proxy object itself instead of on self.


setattr(a, b, c) is not syntactic sugar for a.__setattr__(b, c). setattr and regular attribute assignment both look for a __setattr__ method through a direct search of an object’s type’s method resolution order (a carefully-ordered list of the class and all superclasses), bypassing both the instance dict and __getattribute__/__getattr__ hooks.

In contrast, a.__setattr__(b, c) just performs a regular attribute lookup for __setattr__, so it goes through __getattribute__ and __getattr__, and it checks the instance dict unless __getattribute__ says not to.


super implements a custom __getattribute__ method to do its attribute magic. super().__setattr__ uses this hook, finding C‘s superclass’s __setattr__ and binding self, resulting in a method object for setting attributes on self.

setattr(super(), ...) bypasses __getattribute__. It performs the direct MRO search mentioned previously, searching through super‘s MRO, resulting in a method object for setting attributes on the super instance itself. The super instance doesn’t have a __dict__ to store arbitrary attribute data in, so trying to set a foo attribute fails with a TypeError.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement