9

Dive into Python -

Guido, the original author of Python, explains method overriding this way: "Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it. (For C++ programmers: all methods in Python are effectively virtual.)" If that doesn't make sense to you (it confuses the hell out of me), feel free to ignore it. I just thought I'd pass it along.

I am trying to figure out an example for: a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it

class A:      
  def foo(self): print 'A.foo'      
  def bar(self): self.foo()                  

class B(A):      
  def foo(self): print 'B.foo'     

if __name__ == '__main__': 
  a = A()                
  a.bar()                   # echoes A.foo
  b = B()
  b.bar()                   # echoes B.foo

... but both of these seem kind of obvious.

am I missing something that was hinted out in the quote?


UPDATE

edited typo of calling a.foo() (instead of a.bar())and b.foo() (instead of b.bar()) in the original code

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Vaibhav Bajpai
  • 16,374
  • 13
  • 54
  • 85

2 Answers2

9

Note, this won't work for private methods in Python 3.6:

class A:      
  def __foo(self): print 'A.foo'      
  def bar(self): self.__foo()                  

class B(A):      
  def __foo(self): print 'B.foo'     

if __name__ == '__main__': 
  a = A()                
  a.bar()                   # echoes A.foo
  b = B()
  b.bar()                   # echoes A.foo, not B.foo

I spent an hour to find out the reason for this

8

Yes, you're missing this:

b.bar()   # echoes B.foo

B has no bar method of its own, just the one inherited from A. A's bar calls self.foo, but in an instance of B ends up calling B's foo, and not A's foo.

Let's look at your quote again:

a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it

To translate:

bar (method of A, the base class) calls self.foo, but may in fact end up calling a method of the derived class that overrides it (B.foo that overrides A.foo)

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
  • oops! I made a blunder, I meant `b.bar()` both times in the original code: (and it still seemed obvious, since B inherits A, it has `bar()` too but I just cannot see it. Moreover since I am explicitly passing `self` it is clear it's B' object) – Vaibhav Bajpai Jul 08 '11 at 06:57
  • 1
    @Vaibhav: if this seems obvious, then good - what else? In C++, by the way, unless the methods are virtual it won't work this way. So it's not globally obvious. In Python, thinking in C++'s terms, all methods are virtual – Eli Bendersky Jul 08 '11 at 07:03
  • should I change my code to reflect the original question? (but I don't want to be rude since your answer corresponds to this one) – Vaibhav Bajpai Jul 08 '11 at 07:11
  • 1
    @Vaibhav: I guess you can change it, just note it explicitly with "Update". The important thing is that I hope you no longer are confused – Eli Bendersky Jul 08 '11 at 08:34