Reputation: 10800
I'm extremely new to python, so hopefully I'm not missing too much requisite knowledge to understand this, but...
I have a class with some properties, and I'm trying overriding the setter on one of them similar to this example:
class Foo(object):
def __init__(self):
self._x = True
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
class Bar(Foo):
@property
def x(self):
return super().x
@x.setter
def x(self, value):
print('x set')
super(Bar, self.__class__).x.fset(self, value)
bar = Bar()
# Prints 'x set' as expected:
bar.x = True
This works fine, but I really don't understand why this line works the way it does...
super(Bar, self.__class__).x.fset(self, value)
...and how it differs from this line, which doesn't work:
super(Bar, self).x.fset(self, value)
Any guidance would be appreciated.
Upvotes: 3
Views: 175
Reputation: 532093
To simplify things, we'll assume (as in your example) that super
always returns a proxy for something defined in Foo
, that is, there are no other classes involved.
Ignore the call to super
for the moment, consider the difference between bar.x
and Bar.x
. The first would invoke the getter for the named property; the latter is just a reference to the property itself.
Now consider a non-property attribute. super(Bar, self).method
would be an instance of a bound method, such that super(Bar, self).method(x)
would be equivalent to Foo.method(self, x)
. super(Bar, self.__class__).method
, however, would be the unbound method, i.e. simply Foo.method
.
Now combine steps 1 and 2. We know that bar.x
will cause the getter defined in Bar
to be called, and we know that super(Bar, self)
is a proxy for Foo
via self
. Therefore, super(Bar, self).x
must call the getter defined not in Bar
, but in Foo
.
We also know that Bar.x
is simply a reference to a property
object, one that doesn't invoke its getter; and we know that super(Bar, self.__class__)
acts as a proxy for Foo
independent of any particular object. Therefore, we can conclude that super(Bar, self.__class__).x
, for an instance self
of Bar
, is a reference to the property
object defined in Foo
.
Upvotes: 2