Python calling extended child method from parent - python

I'm trying to call a parent method, and then the extended child method from the parent class in python.
Goal: Create a child method, that inherits a Parent. in the Parent's init it calls one of it's own methods. The parent method should do something, then call the child version of the same method (of the same name) to extend the functionality. The child method of the same name will never be called directly. This is for python 2.7
Absolute worst case I can just add more kwargs to modify the functionality of the Parent method_a, but I would rather have it much more abstract. Example code below.
def Parent(object):
def __init__(self):
print('Init Parent')
self.method_a()
def method_a():
print('parent method')
# potentially syntax to call the Child method here
# there will be several Child classes though, so it needs to be abstract
def Child(Parent):
def __init__(self):
super(Child).__init__(self)
def method_a():
print('child method')
obj = Child()
# expected output:
'Init Parent'
'parent method'
'child method'
Thanks!
EDIT: chepner's answer did work (and may be more correct) but the code I was using to test with was wrong, and this behavior does work in python. Python will call Child's method_a function rather than the Parent one, and then in Child's method_a you can call the Parent first with super(Child, self).method_a() and everything will work fine!
# with the same parent method as above'
def Child(Parent):
def method_a():
# call the Parent method_a first
super(Child, self).method_a()
print('child method')
c = Child()
# output:
'Init parent'
'parent method'
'child method'
This works, but chepner's method might still be more correct (with an abstracted method_a_callback() method in Parent)

The parent class shouldn't rely on or require knowledge about a child class. You can, however, impose a requirement on a child class to implement a certain method.
class Parent:
def __init__(self):
print('Init parent')
self.method_a()
def method_a(self):
print('parent method')
self.method_a_callback()
# The child should override this to augment
# the behavior of method_a, rather than overriding
# method_a entirely.
def method_a_callback(self):
pass
class Child(Parent):
def method_a_callback(self):
print('child method')

Related

Mock super().__init__

I have a parent class that, within its __init__ calls some internal class methods:
class Parent:
def __init__(self):
...
my_method()
def my_method(self, a...):
pass
Afterwards, I create a child class that relies on that Parent class. After creating instance objects of the Child class, they explicitly invoque the parent's __init__ method
class Child(Parent):
def __init__(self, a):
super().__init__(a)
I would like to mock the parent class such that I can test its child without fully relying on the parent's initialization function, which calls my_method. This my_method is problematic and causes the test of the Child to fail due to its parent necessarily calling that method.
Answers with pytest would be appreciated
A simple way to prevent the parent class from calling my_method during initialization, would be to pass an extra argument to the __init__ function of the parent that specifies whether the method should be called.
class Parent:
def __init__(self, call_method=True):
...
if call_method:
my_method()
def my_method(self, a...):
pass
And then in the child class:
class Child(Parent):
def __init__(self, a, call_method=True):
super().__init__(call_method)
When instantiating Child classes during testing, simply set call_method to false.
child = Child(call_method=False)

Multiple Inheritance and calling methods from different parents with the same name

I am trying to understand how Python multiple inheritance work, especially on the MRO side.
Looking at the example below.
class ParentOne:
def __init__(self):
self.one = 1
def echo(self):
print('this is ParentOne class')
self.one += 1
class ParentTwo:
def __init__(self):
self.two = 2
def echo(self):
print('this is ParentTwo class')
self.two += 2
class Child(ParentOne, ParentTwo):
def __init__(self):
super(Child, self).__init__()
self.x = 1
def run(self, x):
self.x = x
if self.x == 1:
ParentOne.echo(self)
else:
ParentTwo.echo(self)
if __name__ == '__main__':
c = Child()
c.run(2)
I can get the 'this is ParentTwo class' output, but is it appropriate to use ParentOne(self) and ParentTwo(self) in this way? or any other way to call the different parent class methods with the same name?
edit: just tried, if there is some variables that is not usable in child class, passing self will cause error.
AttributeError: 'Child' object has no attribute 'two'
So is there any method to call the same method name in different parent class?
You call superclass methods by using:
super().echo()
Note that in the past this was more explicit and this format can still be used. Since it also allows to 'skip' a parent's method by calling his parent class.
super(Child, self).echo() # call echo of superclass of Child, depending on MRO
super(ParentTwo, self).echo() # would call echo on whatever class ParentTwo inherited from but not call ParentTwo.echo
But, which one of the two is called depends on the order of inheritance, since that defines the MRO (Method resolution order). So the first superclass method is called first.
Instead of copy/pasting, I'll just forward you to a site that explains it really well in my opinion; Realpython.com
But I think that deciding for yourself which super class method you want to call will make for unclear coding. And readable code is a very big pro.

what is the Use of Super() in child class even we are not passing any argument

class Base(object):
def __init__(self):
self.fname="MS"
self.lname="Dhoni"
class Child(Base):
def __init__(self):
self.fname="kohli"
super(Base).__init__()
What is use of super method in above code even commenting the super(Base).__init__() I am getting output kohli
please explain
You're calling super(Base) which means the parent of Base class who is object class, so you're not calling the Base.__init__ method, which means no re-assignment of fname which stays to kohli
What you want is parent of Child class, with current instance self
super(Child, self).__init__()
But in fact you can just do the following, that's the same
super().__init__()

Create child class object in parent class

is it a good design to create object of child class in parent like the example below, it seems to be working but is it a good design, is there a better way to do that?
class parent(object):
def __init__(self):
print('Im running')
def execute(self):
x = child()
x.run()
x.myfun()
def myfun(self):
print('parent function')
def run(self):
print('parent running')
class child(parent):
def __init__(self):
super().__init__()
print('Im running too')
def run(self):
print('child running')
f = parent()
f.execute()
This is definitely not a good design for your problem, and not a good design generally (bar exceptions which I cannot think of any), and is definitely against OOP design and SOLID principles.
Simply in OOP design, or any other software engineering frame of mind, you want clear relations. This makes the relationship between your parent class and your child class inherently more complex. Not to mention most of the other languages (at least languages which run complied code) would not allow such thing to happen.
If you need to have an instance of one in the other and vice versa, maybe inheritance was the wrong pattern to begin with, since your classes seem to be connected in a two-way manner unlike scenarios in which inheritance is employed.
The fact that execute doesn't use self at all suggests it should be a class method, in which case you can use whichever class is actually provided to instantiate x.
Once you've done this, the definition of Parent no longer relies on any particular subclass; in fact, it doesn't rely on the fact that Parent is subclassed at all; Parent.execute() will continue to work.
For example,
class Parent:
def __init__(self):
print('Im running')
#classmethod
def execute(cls):
x = cls()
x.run()
x.myfun()
def myfun(self):
print('parent function')
def run(self):
print('parent running')
class Child(Parent):
def __init__(self):
super().__init__()
print('Im running too')
def run(self):
print('child running')
Child.execute()
This will output
Im running
Im running too
child running
parent function
Since Child.execute isn't defined, it resolves to Parent.execute. But Child is still the first argument passed. As a result, x will be an instance of Child, not Parent. x.run() thus runs Child.run, but x.myfun() runs Parent.myfun.
The fact that Parent.execute, though, still depends on x having an attribute specific to cls suggests that you should defer restrict execute to using only things defined by Parent, and let a child override execute to add any child-specific behavior.
Or, execute should be an instance method, but it should simply call self.fun, putting the burden on the caller to call execute with an appropriate object.
c = Child()
c.execute()

Python : super key word calling from child class

class Parent01(object):
def foo(self):
print("Parent01")
pass
class Parent02(object):
def foo(self):
print("Parent02")
pass
class Child(Parent01,Parent02):
def foo(self):
print("Child")
super(Parent01, self).foo()
pass
c = Child()
c.foo()
Output:
Child
Parent02
Why here is the output Parent02?
You're misusing super. You're supposed to name your own class, not a parent. And given this is Python 3, you don't even need to do that, a simple:
super().foo()
would work (as long as the first parameter to the function is a single argument, regardless of name; there are exceptions for when you're accepting self via *args, but that's rare, and only for complicated cases involving simulating a dict).
The reason it misbehaves as written is that you've told it explicitly you're doing super based in Parent01, not Child, so it scans the MRO (method resolution order) to find the next class after Parent01, which happens to be Parent02.

Categories

Resources