Konstantin
Konstantin

Reputation: 3159

Overridden vs. virtual class methods in Python

As far as I understand, in Python methods of parent class are overridden. So all class methods are virtual by default as can be seen from the code below.

class Parent(object):

    def Method1(self):
        print 'FOO'

class Child(Parent):

    def Method1(self):
        print 'BAR'

myInstance = Child()

#Overridden method is called
myInstance.Method1()                             # BAR

#Is it possible to do the following?
myInstance.{something}                           # FOO

QUESTIONS:

Upvotes: 1

Views: 891

Answers (3)

Martijn Pieters
Martijn Pieters

Reputation: 1124110

You call parent methods by having the super() function search for the next method in the MRO (method resolution order):

class Child(BaseClass):
    def Method1(self):
        print 'BAR'
        super(Child, self).Method1()  # will call BaseClass.Method1

where self is the instance reference, so super(type(myInstance), myInstance).Method1() would achieve the same thing from outside the method.

Or you can access the unbound method on the class, and pass in the instance explicitly; you'd be able to do this outside the method too:

BaseClass.Method1(myInstance)

because now you referenced the method attribute directly on the class instead, and passed in the instance as an explicit self to that method; you'd use self from inside a method on Child there.

Python attributes (methods are attributes too) are looked up by name and such look-ups search through the instance, then the class of the instance, then through each parent class until a match is found; the signature of a method doesn't come into play here.

You can still override a method in a child class, change the signature, but remain compatible with the parent method by using keyword arguments:

class Child(BaseClass):
    def Method1(self, x=None, y=None):
        if x is None and y is None:
            # arguments left at defaults, call base method
            return super(Child, self).Method1()

        print 'BAR: {} and {}'.format(x, y)

Now if you call myInstance.Method1(), with no arguments, the BaseClass.Method1() method is called, pass in arguments and something else happens instead.

Upvotes: 2

chepner
chepner

Reputation: 532053

In addition to using super, there are a couple of explicit options that bypass the MRO:

# Explicitly call Baseclass.Method1, passing your instance as the argument
BaseClass.Method1(myInstance)

# Call Method1 on the (first) base class of the instance.
# This is ugly; don't actually write code like this
# x.__class__.__bases__[0] is just another way to get a reference
# to BaseClass; otherwise, this is identical to the previous option,
# hence the need to repeat myInstance
myInstance.__class__.__bases__[0].Method1(myInstance)

Upvotes: 1

Esteban Küber
Esteban Küber

Reputation: 36852

Is it possible to call parent method Parent.Method1() from the instance myInstance of the child class?

You can call the method directly, and pass your instance as first argument:

>>> class A(object):
...     def foo(self):
...         print 'foo'
...
>>> class B(A):
...     def foo(self):
...         print 'bar'
...
>>> b = B()
>>> A.foo(b)
foo

Is it possible to make def Parent.Method1(self) not to be overridden by a method with the same name, but some different set of arguments def Child.Method1(self,x,y)?

Yes, you use super and call the parent's method directly:

>>> class A(object):
...     def foo(self, bar='bar'):
...         print bar
...
>>> class B(A):
...     def foo(self):
...         super(B, self).foo(bar='foo')
...
>>> B().foo()
foo
>>> A().foo()
bar

Upvotes: 1

Related Questions