According to this answer:
setattr(instance, name, value)
is syntactic sugar forinstance.__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?
The answer you linked to glosses over some important details. Long story short,
setattr
bypassessuper
's magic, so it tries to set attributes on thesuper()
proxy object itself instead of onself
.setattr(a, b, c)
is not syntactic sugar fora.__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, findingC
's superclass's__setattr__
and bindingself
, resulting in a method object for setting attributes onself
.setattr(super(), ...)
bypasses__getattribute__
. It performs the direct MRO search mentioned previously, searching throughsuper
's MRO, resulting in a method object for setting attributes on the super instance itself. Thesuper
instance doesn't have a__dict__
to store arbitrary attribute data in, so trying to set afoo
attribute fails with aTypeError
.