Perico de los palotes
Perico de los palotes

Reputation: 211

Calling an overridden method, superclass an calls overridden method

This code throws an exception, AttributeError, "wtf!", because A.foo() is calling B.foo1(), shouldn't it call A.foo1()? How can I force it to call A.foo1() (and any method call inside A.foo() should call A.*)

class A(object):
    def foo(self):
        print self.foo1()

    def foo1(self):
        return "foo"

class B(A):
    def foo1(self):
        raise AttributeError, "wtf!"

    def foo(self):
        raise AttributeError, "wtf!"

    def foo2(self):
        super(B, self).foo()

myB = B()
myB.foo2()

Upvotes: 21

Views: 31753

Answers (4)

Clinton Mah
Clinton Mah

Reputation: 1

One can see what Python is doing here, but the manner of overriding is a bit extreme. Take the case when class A defines 100 attributes and class B inherits these and add 1 more attribute. We want to be able to have the __init__() for B call the __init__() for A and let B's code define only its single attribute. Similarly, if we define a reset() method in A to set all attributes to zero, then the corresponding reset() method for B should be able just to call the reset() method for A and then zero out the single B attribute instead of having to duplicate all of A's code. Python is making difficult what is supposed to be a major advantage of object-oriented programming; that is, the reuse of code. The best option here is avoid overriding of methods that we really want to reuse. If you want to get a sense of the complications with Python here, try this code:

class X(object):
    def __init__ ( self ):
        print "X"
        self.x = 'x'
        self.reset()
        print "back to X"
    def reset ( self ):
        print "reset X"
        self.xx = 'xx'

class Y(X):
    def __init__ ( self ):
        print "Y"
        super(Y,self).__init__()
        self.y = 'y'
        self.reset()
        print "back to Y"
    def reset ( self ):
        print "reset Y"
        super(Y,self).reset()
        print "back to reset Y"
        self.yy = 'yy'

aY = Y()

(To make this work properly, remove the self.reset() call in __init__() for class Y.)

Upvotes: -1

Mikko Ohtamaa
Mikko Ohtamaa

Reputation: 83358

It is working as intended, as 100% of world programming languages work. Subclass overrides ALL methods of parent class.

However if you really really want to call the A.foo1() you might be able to do it like this (I cannot guarantee). And in any case you must not do this as this is against all principles of good programming.

 class A(object):

    def foo(self):
        A.foo1(self)

Upvotes: 6

Ethan Furman
Ethan Furman

Reputation: 69041

In class A instead of calling self methods you need to call A methods and pass in self manually.

This is not the normal way of doing things -- you should have a really good reason for doing it like this.

class A(object):
    def foo(self):
        print A.foo1(self)

    def foo1(self):
        return "foo"

class B(A):
    def foo1(self):
        raise AttributeError, "wtf!"

    def foo(self):
        raise AttributeError, "wtf!"

    def foo2(self):
        super(B, self).foo()

myB = B()
myB.foo2()

Upvotes: 13

extraneon
extraneon

Reputation: 23950

In the code:

def foo2(self):
    super(B, self).foo()

self is an instance of B.

When a method derived from A is called by an instance of B it will start looking in the namespace from B, and only if the method is not found (e.g. is not overridden by B) the implementation from A is used, but always with self referring to B. At no point self is an instance of A.

Upvotes: 7

Related Questions