Mock super().__init__ - python

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)

Related

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__()

In python, how to have two classes share implementation of a method that calls another method with specific implementations for each class

Suppose I have a parent class Parent, with abstract method load that is implemented in its childs classes. Now, I have two child classes childA and childB, both inheriting from Parent. The implementation of load for childA and childB identical. But this implementation of load calls another method, get_paths, that is specific to childA and childB. Parent is something like:
from abc import ABC, abstractmethod
class Parent(ABC):
def __init__(self, *params):
# set up the params
#abstractmethod
def load(self, *params):
# loads files, according to each children
def process(self, *params):
# process the loaded files
And then the children:
class childA(Parent):
def __init__(self, *paramsP, *paramsA):
super().__init__(*paramsP)
# Set up the specific paramsA
def get_paths(self, *params):
# specific implementation to childA
def load(self, *params):
# Calls the self.get_paths method, identical to childB.load
class childB(Parent):
def __init__(self, *paramsP, *paramsB):
super().__init__(*paramsP)
# Set up the specific paramsB
def get_paths(self, *params):
# specific implementation to childB
def load(self, *params):
# Calls the self.get_paths method, identical to childA.load
How can I reuse the code from load in both childA and childB, but have the get_paths implementation be specific to each class? I tried two approaches:
(1) Have childB inherit from childA instead, and override the implementation of get_paths. In this approach, I have:
class childB(childA):
def __init__(self, *paramsP, *paramsB):
super().__init__(*paramsP)
# Set up the specific paramsB
def get_paths(self, *params):
# specific implementation to childB
I called it as:
b = childB(...)
b.load(...)
However, when I call `childB.load`, the `get_paths` called inside of it is `childA.get_paths`. I noticed that because I was getting an error when running `b.load`, so tried putting a break point with `ipdb` inside of `childB.get_paths`, but execution did not stop. But when I put the breaking point inside of `childA.get_paths`, it did break.
(2) Implement another class, `AB`, with the following definition:
```python
class AB(Parent):
def __init__(self, *paramsP):
super().__init__(*paramsP)
#abstract method
def get_paths(self, *params):
# To be implemented in childA and childB
def load(self, *params):
# Implements the load from childA and childB
and then have childA and childB both inherit from AB instead, and implement their specific get_paths. However, this did not work as well, as I get the error: TypeError: Can't instantiate abstract class ChildB with abstract methods _AB__get_paths.
It is important to add I cannot implement load in Parent because there are other classes ( childC, childD, ...) with unique load implementations.. I just want to reuse this code between childA and childB
So, what is the correct way to solve this?
Unless you want Parent to be inherited with abstract .load, just put implementation into Parent.
If .load is common only for this two childs – you can inherit from Parent with 3rd child like LoadMixin and inherit both Parent and mixin
One approach would be:
class LoadableChild(Parent):
def load(self, *params): ...
class childA(LoadableChild):
def get_paths(self, *params): ...
class childB(LoadableChild):
def get_paths(self, *params): ...
Another is:
class LoadBase:
def load(self, *params): ...
class childA(LoadBase, Parent):
def get_paths(self, *params): ...
class childB(LoadBase, Parent):
def get_paths(self, *params): ...
Note the order of inheritance in later approach, if you inherit parent as first superclass, there is no easy way around:
if your mixin inherits Parent – there's no unambiguous MRO
if mixin inherits object – there's instantiation error on abstract .load.
It's matter of preference, I'd say, for me personally first approach is cleaner

Init functions execution in multiple inheritance in python

I am new to python and trying to understand the inheritance in python. Python has a feature of multiple inheritance. A single class can inherit more than one class at a same time. When we create an object of child class,the init function of child class is called. I want to call the init function of both the parent class of the child, but i am able to call only only one init function.I read the concept of method resolution order, by which the left most class inherited init function will be called. Please correct my code, so that the init function of both parent classes is called.
class A:
def __init__(self):
print("in A Init")
class B:
def __init__(self):
print("in B Init")
class C(B,A):
def __init__(self):
super().__init__()
print("in C Init")
cObj= C()
All the __init__ functions need to call super().__init__(), like this:
class A:
def __init__(self):
super().__init__()
print("in A Init")
class B:
def __init__(self):
super().__init__()
print("in B Init")
class C(B, A):
def __init__(self):
super().__init__()
print("in C Init")
c_obj= C()
When you invoke this you get the following output:
in A Init
in B Init
in C Init
Per the super() function documentation, it returns a reference to "a parent or sibling" of the class, whichever is next in the method resolution order. At the top of the hierarchy, it returns a reference to the implicit parent class object, which has an empty __init__ method which does nothing.
In order for this to work well, it's best for all the inherited __init__ functions to have the same signature, including the common base class; in this case, the signature is just __init__(self) (no additional arguments), and the common base class is object, which also has __init__(self) with no additional arguments, so that's all good. Another common pattern is for them all to take keyword arguments and pass through **kwargs to the next one.

Python calling extended child method from parent

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')

How to make sure parent method is always called before child overrides it in a decorator?

So I have a parent class:
class Parent(Object):
def function(self):
do_something()
And many child classes:
class Child1(Parent):
def function(self):
do_something_else_1()
class Child2(Parent):
def function(self):
do_something_else_2()
...
I would like to ensure that the parent function() is always called before the children's function(), so that every call to function() also calls do_something() no matter the class. Now, I know I can do something like:
class Child1(Parent):
def function(self):
super(Child1, self).function()
do_something_else_1()
class Child2(Parent):
def function(self):
super(Child2, self).function()
do_something_else_2()
...
but I would rather not do that for every child class, because these child classes are being generated on the fly, and because these child classes themselves are being extended further. Instead, I would like to do something that looks like
class Child1(Parent):
#call_parent
def function(self):
do_something_else_1()
class Child2(Parent):
#call_parent
def function(self):
do_something_else_2()
...
And write a decorator to accomplish the same task.
I have two questions:
Is this even a good idea? Am I using decorators and function overriding in their intended way?
How would I go about writing this decorator?
Is this even a good idea? Am I using decorators and function overriding in their intended way?
This question is complex to answer without knowing the details about your system.
Just from the abstract example it looks OK, but replacing the explicit and clear super() call with something like #call_parent is not a good idea.
Everyone knows or can easily find out what super() does and decorator will only cause the confusion.
How would I go about writing this decorator?
Don't write the decorator, instead you can use the template method:
class Parent(Object):
def function(self):
do_something()
do_something_in_child()
def do_something_in_child():
pass
Now in child classes you only override the do_something_in_child, the function stays only in the Parent, so you are sure your do_something() is always called.
class Child1(Parent):
def do_something_in_child(self):
do_something_else_1():
class Child2(Parent):
def do_something_in_child(self):
do_something_else_2():
class Child3(Parent):
# no override here, function() will do the same what it does in Parent
pass
Im not well versed on Python but you could so something like:
# Function in childredn. Overrides parent one.
def function(self):
# child code
super().function() #however it is used
# more child code
If that is not plausible, take a look on template method design pattern.
# Function in parent. Do not override this one
def function(self):
# your parent code
function_do_something()
# more code if you need it
# function in parent. Children overryde this one
def function_do_something():
...
And, you can allways let function_do_something() be void, in order to only execute your father constructor.

Categories

Resources