So I have this:
class Parent(object):
def __init__(self, val):
print 'enter Base init'
self._set_x(val)
print 'leave Base init'
def _get_x(self):
return self._x
def _set_x(self, val):
print 'enter Base _set_x'
self._x = val
print 'leave Base _set_x'
x = property(_get_x, _set_x)
class Child(Parent):
def _set_x(self, val):
print 'enter Child _set_x'
y = val * 2
super(Child, self)._set_x(y)
print 'leave Child _set_x'
child = Child(5)
num = child.x
child.x = 5
print num == child.x
And when I run it, I get this:
enter Base init
enter Child _set_x
enter Base _set_x
leave Base _set_x
leave Child _set_x
leave Base init
enter Base _set_x
leave Base _set_x
False
I’ve been reading around, and people are saying that the overriding shouldn’t work, but my question is why is there this seeming inconsistency here? The subclass’ setter gets called when calling from init, but when you later act on the already initialized object, it calls the base’s setter. Can someone explain what is going on here?
Because you call it inconsistently — once directly, and once via a property. Change
self._set_x(x)inParent.__init__toself.x = xand you’ll seeChild._set_xis never called. To override a setter in a child class, you can useproperty.setteras decorator:Or add a level of indirection to the property:
The overriding doesn’t work directly, because property stores concrete method objects (
Parent._get_xandParent._set_x), and doesn’t look them up again, even if the type of the object happens to change — the code that runs is the same regardless. Indirection forces lookup in the dynamic type ofself, which allows for overriding.