469,354 Members | 2,321 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,354 developers. It's quick & easy.

OOP: method overriding works in mysterious ways?

Consider the following:

#!/usr/bin/python

#-----------------------------------------------------------------
class Grand_parent( object ):

def speak( self ):
print 'Grand_parent.speak()'
self.advise()

def advise( self ):
print 'Grand_parent.advise()'
self.critique()

def critique( self ):
print 'Grand_parent.critique()'
#-----------------------------------------------------------------
class Parent( Grand_parent ):

def speak( self ):
print '\tParent.speak()'
self.advise()

def advise( self ):
print '\tParent.advise()'
self.critique()

# ATM, the Parent is at a loss for words, and has no critique.
#-----------------------------------------------------------------
class Child( Parent ):

def speak( self ):
print '\t\tChild.speak()'
self.advise()

# Currently, the Child has no really useful advice to give.

def critique( self ):
print '\t\tChild.critique()'
#-----------------------------------------------------------------
print 'speak() calls advise(), then advise() calls critique().'
print

people = [ Grand_parent(), Parent(), Child() ]
for person in people:
person.speak()
print

====================
The output is:

speak() calls advise(), then advise() calls critique().

Grand_parent.speak()
Grand_parent.advise()
Grand_parent.critique()

Parent.speak()
Parent.advise()
Grand_parent.critique()

Child.speak()
Parent.advise()
Child.critique()
What's going on here with that last "Child.critique()"? The
Parent called self.critique(), and since it *had* no critique()
method, it should've deferred to it's parent's critique()
method, right? But instead, somehow Child.critique() got called.
Why?

---J

--
(remove zeez if demunging email address)
Jan 2 '06 #1
11 1434
Parent.critique() is calling self.critique(), which has been overriden
by Child.critique() instead of Parent.critique. It makes perfect sense
to me.

Jan 2 '06 #2
Oh, I see what you mean. From my experience, the methods are passed
down, not referred to from the parent. That is, Parent does have its
own critique method, not a reference to Grand_parent.critique(). So
when Child calls self.advise, it is calling its inherrited copy. Then,
since the inherited Child.advise() from Parent.advise() calls
self.critique, it calls it's own overriden critique method.

I hope this makes sense.

Jan 2 '06 #3
John M. Gabriele wrote:
Consider the following:
[snip]
#-----------------------------------------------------------------
class Parent( Grand_parent ):

def speak( self ):
print '\tParent.speak()'
self.advise()

def advise( self ):
print '\tParent.advise()'
self.critique()

# ATM, the Parent is at a loss for words, and has no critique.
#-----------------------------------------------------------------
class Child( Parent ):

def speak( self ):
print '\t\tChild.speak()'
self.advise()

# Currently, the Child has no really useful advice to give.

def critique( self ):
print '\t\tChild.critique()'


Since Child has no advice() method, it inherits the one for Parent.
Thus, Child can be thought of as being defined as follows:

.. class Child( Parent ):
..
.. def speak( self ):
.. print '\t\tChild.speak()'
.. self.advise()
..
.. def advise( self ): # inherited from Parent
.. print '\tParent.advise()'
.. self.critique()
..
.. def critique( self ):
.. print '\t\tChild.critique()'
..
Note that "self" refer to the *instance* created, not the *class*.
print 'speak() calls advise(), then advise() calls critique().'
print

people = [ Grand_parent(), Parent(), Child() ]
for person in people:
person.speak() ### calls the instance's relevant method
print
[snip]
Child.speak()
Parent.advise() #inherited from Parent
Child.critique()



Now, does the output make sense?

André

Jan 2 '06 #4
> it calls it's own overriden critique method

(overriden meaning the one that did the overriding)

Jan 2 '06 #5
Dustan wrote:
.... From my experience, the methods are passed
down, not referred to from the parent. That is, Parent does have its
own critique method, not a reference to Grand_parent.critique().

This is typical of static binding as (for example) seen in C++. If you
think of dynamically bound systems like Smalltalk, Ruby, and Python, the
more unusual case is wanting to go up the hierarchy (where you use super
to get the behavior you are apparently expecting). Think of Python's
method dispatch as always being "virtual".

--Scott David Daniels
sc***********@acm.org
Jan 2 '06 #6
Scott David Daniels wrote:
Dustan wrote:
.... From my experience, the methods are passed
down, not referred to from the parent. That is, Parent does have its
own critique method, not a reference to Grand_parent.critique().
This is typical of static binding as (for example) seen in C++. If you
think of dynamically bound systems like Smalltalk, Ruby, and Python, the
more unusual case is wanting to go up the hierarchy (where you use super
to get the behavior you are apparently expecting). Think of Python's
method dispatch as always being "virtual".


Ah. Not only that, but the other ingredient (I think) is to keep in mind
that you're always calling instance methods via the self object -- and
that self object is always the same object regardless of how far up the
inheritance tree you go with those method calls, right?
--Scott David Daniels
sc***********@acm.org


---J
--
(remove zeez if demunging email address)
Jan 2 '06 #7
Dustan wrote:
[snip] That is, Parent does have its
own critique method, not a reference to Grand_parent.critique().
Interesting. "It has its own" critique method? Hm. Not quite sure what
that means exactly...

Anyhow, I wasn't suggesting that Parent had a reference to
Grand_parent.critique(), only that Python would search *up* the tree
looking for the method it's looking to call.

Thanks!
So
when Child calls self.advise, it is calling its inherrited copy. Then,
since the inherited Child.advise() from Parent.advise() calls
self.critique, it calls it's own overriden critique method.

I hope this makes sense.

--
(remove zeez if demunging email address)
Jan 2 '06 #8
André wrote:
John M. Gabriele wrote:

Since Child has no advice() method, it inherits the one for Parent.
Thus, Child can be thought of as being defined as follows:

. class Child( Parent ):
.
. def speak( self ):
. print '\t\tChild.speak()'
. self.advise()
.
. def advise( self ): # inherited from Parent
. print '\tParent.advise()'
. self.critique()
.
. def critique( self ):
. print '\t\tChild.critique()'
.
That's a very interesting way to look at it... But I thought
that the Python interpreter takes care of walking up the
inheritance tree looking for the instance methods, rather
than what you've written above...
Note that "self" refer to the *instance* created, not the *class*.
Thanks. Right -- the self object always refers to the object that
you originally used to call the instance method (here, speak()).

Now, does the output make sense?

André


Bearing in mind what self is referring to, then yes,
the output does make sense. Thanks. :)

---J

--
(remove zeez if demunging email address)
Jan 2 '06 #9
"John M. Gabriele" <jo************@yahooz.com> writes:
Consider the following:

#!/usr/bin/python

#-----------------------------------------------------------------
class Grand_parent( object ):

def speak( self ):
print 'Grand_parent.speak()'
self.advise()

def advise( self ):
print 'Grand_parent.advise()'
self.critique()

def critique( self ):
print 'Grand_parent.critique()'
#-----------------------------------------------------------------
class Parent( Grand_parent ):

def speak( self ):
print '\tParent.speak()'
self.advise()

def advise( self ):
print '\tParent.advise()'
self.critique()

# ATM, the Parent is at a loss for words, and has no critique.
#-----------------------------------------------------------------
class Child( Parent ):

def speak( self ):
print '\t\tChild.speak()'
self.advise()

# Currently, the Child has no really useful advice to give.

def critique( self ):
print '\t\tChild.critique()'
#-----------------------------------------------------------------
print 'speak() calls advise(), then advise() calls critique().'
print

people = [ Grand_parent(), Parent(), Child() ]
for person in people:
person.speak()
print

====================
The output is:

speak() calls advise(), then advise() calls critique().

Grand_parent.speak()
Grand_parent.advise()
Grand_parent.critique()

Parent.speak()
Parent.advise()
Grand_parent.critique()

Child.speak()
Parent.advise()
Child.critique()
What's going on here with that last "Child.critique()"? The
Parent called self.critique(), and since it *had* no critique()
method, it should've deferred to it's parent's critique()
method, right? But instead, somehow Child.critique() got called.
Why?


Because that's the way Python searchs for object attributes. Nobody
made it explicit, so I will. This is simplified, ignoring various
complications:

When looking up a value for self.foo, you first look for
attribute foo of self. You then check the class of self for
attribute foo. You then check the parent class of the last
class you checked for attribute foo. You repeat that last step
until there is no parent class.

Like I said, that's simplified. But it's sufficent to explain what
you're seeing.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jan 3 '06 #10
John M. Gabriele a écrit :
Consider the following:

#!/usr/bin/python

#-----------------------------------------------------------------
class Grand_parent( object ):

def speak( self ):
print 'Grand_parent.speak()'
self.advise()

def advise( self ):
print 'Grand_parent.advise()'
self.critique()

def critique( self ):
print 'Grand_parent.critique()'
#-----------------------------------------------------------------
class Parent( Grand_parent ):

def speak( self ):
print '\tParent.speak()'
self.advise()

def advise( self ):
print '\tParent.advise()'
self.critique()

# ATM, the Parent is at a loss for words, and has no critique.
#-----------------------------------------------------------------
class Child( Parent ):

def speak( self ):
print '\t\tChild.speak()'
self.advise()

# Currently, the Child has no really useful advice to give.

def critique( self ):
print '\t\tChild.critique()'
#-----------------------------------------------------------------
print 'speak() calls advise(), then advise() calls critique().'
print

people = [ Grand_parent(), Parent(), Child() ]
for person in people:
person.speak()
print

====================
The output is:

speak() calls advise(), then advise() calls critique().

Grand_parent.speak()
Grand_parent.advise()
Grand_parent.critique()

Parent.speak()
Parent.advise()
Grand_parent.critique()

Child.speak()
Parent.advise()
Child.critique()
What's going on here with that last "Child.critique()"? The
Parent called self.critique(), and since it *had* no critique()
method, it should've deferred to it's parent's critique()
method, right? But instead, somehow Child.critique() got called.
Why?

---J

Because that's the way virtual methods are supposed to work. When you
can a methon foo on an object, you always start your search from the
current object class and not the class of the current function.
Jan 3 '06 #11
On 1/2/06, Mike Meyer <mw*@mired.org> wrote:
"John M. Gabriele" <jo************@yahooz.com> writes:
Consider the following:

#!/usr/bin/python

#-----------------------------------------------------------------
class Grand_parent( object ):

def speak( self ):
print 'Grand_parent.speak()'
self.advise()

def advise( self ):
print 'Grand_parent.advise()'
self.critique()

def critique( self ):
print 'Grand_parent.critique()'
#-----------------------------------------------------------------
class Parent( Grand_parent ):

def speak( self ):
print '\tParent.speak()'
self.advise()

def advise( self ):
print '\tParent.advise()'
self.critique()

# ATM, the Parent is at a loss for words, and has no critique.
#-----------------------------------------------------------------
class Child( Parent ):

def speak( self ):
print '\t\tChild.speak()'
self.advise()

# Currently, the Child has no really useful advice to give.

def critique( self ):
print '\t\tChild.critique()'
#-----------------------------------------------------------------
print 'speak() calls advise(), then advise() calls critique().'
print

people = [ Grand_parent(), Parent(), Child() ]
for person in people:
person.speak()
print

====================
The output is:

speak() calls advise(), then advise() calls critique().

Grand_parent.speak()
Grand_parent.advise()
Grand_parent.critique()

Parent.speak()
Parent.advise()
Grand_parent.critique()

Child.speak()
Parent.advise()
Child.critique()
What's going on here with that last "Child.critique()"? The
Parent called self.critique(), and since it *had* no critique()
method, it should've deferred to it's parent's critique()
method, right? But instead, somehow Child.critique() got called.
Why?
Because that's the way Python searchs for object attributes. Nobody
made it explicit, so I will. This is simplified, ignoring various
complications:

When looking up a value for self.foo, you first look for
attribute foo of self. You then check the class of self for
attribute foo. You then check the parent class of the last
class you checked for attribute foo. You repeat that last step
until there is no parent class.

Like I said, that's simplified. But it's sufficent to explain what
you're seeing.


If your interested in the non-simplified complicated rules for exactly
how methods are looked up (only different than the simple case when
you get into multiple inheritence), see
http://www.python.org/2.3/mro.html

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
--
http://mail.python.org/mailman/listinfo/python-list

Jan 3 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by Dan | last post: by
5 posts views Thread by John Wood | last post: by
3 posts views Thread by Shawn Ferguson | last post: by
65 posts views Thread by Chris Carlen | last post: by
5 posts views Thread by jmDesktop | last post: by
30 posts views Thread by Yorian | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by suresh191 | last post: by
1 post views Thread by Marylou17 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.