Question about subclassing and overriding methods

F

Frank Millman

Hi all

Assume a simple class -

class Test(object):
def __init__(self,x):
self.x = x
def getx(self):
print self.x

Test(1).getx()
Test(2).getx()
Test(3).getx()

As expected, the results are 1,2,3

Assume a slight variation, where given a particular condition I want a
particular method to behave differently. I know that I could subclass,
but for various reasons I preferred to do it this way -

class Test(object):
def __init__(self,x,y=False):
self.x = x
if y:
self.getx = self.getx2
def getx(self):
print self.x
def getx2(self):
print self.x * 2

Test(1).getx()
Test(2,True).getx()
Test(3).getx()

As expected, the results are 1,4,3

Now assume a subclass of the above class, where I want the method to
behave diferently again -

class Test2(Test):
def __init__(self,x,y=False):
Test.__init__(self,x,y)
def getx(self):
print self.x*3

Test2(1).getx()
Test2(2,True).getx()
Test2(3).getx()

Here I was hoping that the results would be 3,6,9 but they are 3,4,9.

I thought that getx in Test2 would override getx in Test, even if getx
in Test has been replaced by getx2, but clearly that is not happening.
Can someone explain why.

Thanks

Frank Millman
 
F

Frank Millman

Frank said:
Hi all

Assume a simple class -

class Test(object):
def __init__(self,x):
self.x = x
def getx(self):
print self.x

Test(1).getx()
Test(2).getx()
Test(3).getx()

As expected, the results are 1,2,3

Assume a slight variation, where given a particular condition I want a
particular method to behave differently. I know that I could subclass,
but for various reasons I preferred to do it this way -

class Test(object):
def __init__(self,x,y=False):
self.x = x
if y:
self.getx = self.getx2
def getx(self):
print self.x
def getx2(self):
print self.x * 2

Test(1).getx()
Test(2,True).getx()
Test(3).getx()

As expected, the results are 1,4,3

Now assume a subclass of the above class, where I want the method to
behave diferently again -

class Test2(Test):
def __init__(self,x,y=False):
Test.__init__(self,x,y)
def getx(self):
print self.x*3

Test2(1).getx()
Test2(2,True).getx()
Test2(3).getx()

Here I was hoping that the results would be 3,6,9 but they are 3,4,9.

Ok, on reflection I more or less understand what is happening, and I
have found an ugly workaround -

class Test2(Test):
def __init__(self,x,y=False):
getx = self.getx
Test.__init__(self,x,y)
self.getx = getx
def getx(self):
print self.x*3

Test2(1).getx()
Test2(2,True).getx()
Test2(3).getx()

Now I get 3,6,9 as intended.

I would still appreciate any comments, especially if someone can
suggest a better approach.

Thanks

Frank
 
B

Bruno Desthuilliers

Frank said:
Hi all

Assume a simple class -

class Test(object):
def __init__(self,x):
self.x = x
def getx(self):
print self.x

Test(1).getx()
Test(2).getx()
Test(3).getx()

As expected, the results are 1,2,3

Assume a slight variation, where given a particular condition I want a
particular method to behave differently. I know that I could subclass,
but for various reasons I preferred to do it this way -

class Test(object):
def __init__(self,x,y=False):
self.x = x
if y:
self.getx = self.getx2
def getx(self):
print self.x
def getx2(self):
print self.x * 2

Test(1).getx()
Test(2,True).getx()
Test(3).getx()

As expected, the results are 1,4,3

Now assume a subclass of the above class, where I want the method to
behave diferently again -

class Test2(Test):
def __init__(self,x,y=False):
Test.__init__(self,x,y)
def getx(self):
print self.x*3

Test2(1).getx()
Test2(2,True).getx()
Test2(3).getx()

Here I was hoping that the results would be 3,6,9

Why ???
but they are 3,4,9.

Yes, obviously.
I thought that getx in Test2 would override getx in Test,

It does.
even if getx
in Test has been replaced by getx2,

This "replacement" happens at instance initialisation time - ie, after
the class object have been created. If you don't want this to happen,
either skip the call to Test.__init__ in Test2.__init__, or make this
call with False as second param, or redefine getx2 in Test2. Or go for a
saner design...
but clearly that is not happening.
Can someone explain why.

Test2(2,True) calls Test2.__init__() with a Test2 instance 'self' and
y=True. Test2.__init__() then calls Test.__init__() with the same
instance and y=True. So the branch:
if y:
self.getx = self.getx2
is executed on the Test2 instance.

I don't see what puzzle you here.
 
F

Frank Millman

Bruno said:
Frank Millman wrote:

This "replacement" happens at instance initialisation time - ie, after
the class object have been created. If you don't want this to happen,
either skip the call to Test.__init__ in Test2.__init__, or make this
call with False as second param, or redefine getx2 in Test2. Or go for a
saner design...

Thanks, Bruno, you gave me the clue to a less ugly workaround.

In my particular case, when I do subclass Test, y is always True.
Therefore I can rewrite it like this -

class Test2(Test):
def __init__(self,x):
Test.__init__(self,x,True)
def getx2(self):
print x*3

As you suggested, I redefine getx2 instead of getx, and it works as I
want.

Slightly less insane, I hope ;-)

Frank
 
D

Dennis Lee Bieber

In my particular case, when I do subclass Test, y is always True.
Therefore I can rewrite it like this -

class Test2(Test):
def __init__(self,x):
Test.__init__(self,x,True)
def getx2(self):
print x*3

As you suggested, I redefine getx2 instead of getx, and it works as I
want.

Slightly less insane, I hope ;-)

I do hope this is just a simplified example <G>

Otherwise I'd have implemented it the other way around -- don't
compute the value on each get, but rather on the initialization
.... def __init__(self, x, y=False):
.... if y:
.... self.x = x * 2
.... else:
.... self.x = x
.... def getx(self):
.... return self.x
.... .... def __init__(self, x, y=False):
.... Test.__init__(self, x, y) #meaningless here
.... self.x = x * 3
.... #no need to redefine getx()9
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
F

Frank Millman

Dennis said:
I do hope this is just a simplified example <G>

Otherwise I'd have implemented it the other way around -- don't
compute the value on each get, but rather on the initialization

Thanks for the reply, Dennis. In fact, my real requirement has got
nothing to do with computing a value. That was just a way of
illustrating my need to call a different version of a method depending
on certain factors.

I have since come up with a different approach, which I have explained
in a new thread. It is still a bit complicated, so I would still
appreciate any comments on how to simplify it.

Frank
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top