how to write __init__ in python multiple inheritance to instantiate all variables - python

class FakeBase(object):
def __init__(self, *args):
pass
class Parent(FakeBase):
def __init__(self, x=1, *args):
super().__init__(x, *args)
self.var1 = x
class Parent2(FakeBase):
def __init__(self, x=3, y=4, *args):
super().__init__(x, y, *args)
self.var2 = x
self.var3 = y
class Child(Parent, Parent2):
def __init__(self, z, *args):
super().__init__(*args)
self.var4 = z
childObject = Child("var4", "var3", "var1", "var2")
print(childObject.var1)
print(childObject.var2)
print(childObject.var3)
print(childObject.var4)
The result is:
var3
var3
var1
var4
I just started dealing with Python multiple inheritance.
Here, I am only able to call the super().__init__(x) with one parameter. And it will only call the parent's __init__(). I want to initial var2 and var3 also. How to do that?
Getting hits from your answers, I tried to modified my code.
But, still not getting the way to initial all four parameters. And none of your answers did neither.
Thanks and still waiting for the answer.

Here's a solution building on #jonrsharpe's suggestion. Method uses *args signature for generic variables, which are passed to parent(s). The specific variable z is captured separately and used by the class.
source
class parent(object):
var1=1
def __init__(self,x=1):
self.var1=x
class parent2(object):
var2=11
var3=12
def __init__(self,x=3,y=4):
self.var2=x
self.var3=y
def parprint(self):
print(self.var2)
print(self.var3)
class child(parent, parent2):
var4=5
def __init__(self, z, *args):
super(child,self).__init__(*args)
self.var4 = z
childobject = child(9,"var3")
print(childobject.var1)
print(childobject.var2)
print(childobject.var3)
print(childobject.var4)
childobject.parprint()
output
var3
11
12
9
11
12

What's happening is the following:
Child grabs "var4" to its argument z and passes on the args list
["var3", "var1", "var2"] to Parent.
Parent grabs "var3" to its argument x and passes on the x and args list ["var1", "var2"] to Parent2 (so it both grabs and passes the same value "var3").
Parent2 grabs "var3" and "var1" and passes the args list ["var2"] to the FakeBase.
You can use *args if you know the Method Resolution Order (MRO), but the MRO may change if you create new subclasses or superclasses, making your code very unstable. The better way is to use keyword arguments **kwargs instead. Each class grabs the variable it needs and passes along the rest.
class FakeBase(object):
def __init__(self, **kwargs):
pass
class Parent(FakeBase):
def __init__(self, var1=1, **kwargs): # Takes var1 out from **kwargs.
super().__init__(**kwargs) # Passing on the rest {}.
self.var1 = var1
class Parent2(FakeBase):
def __init__(self, var2=3, var3=4, **kwargs): # Takes var2 and var3 out from **kwargs.
super().__init__(**kwargs) # Passing on the rest {var1: "var1"}.
self.var2 = var2
self.var3 = var3
class Child(Parent, Parent2):
def __init__(self, var4, **kwargs): # Takes var4 out from **kwargs.
super().__init__(**kwargs) # Passing on the rest {var1: "var1", var2: "var2", var3: "var3"}.
self.var4 = var4
By writing it this way the MRO doesn't matter and he order of the arguments when initializing Child doesn't matter either:
childObject = Child(var1="var1", var2="var2", var3="var3", var4="var4")
print(childObject.var1, childObject.var2, childObject.var3, childObject.var4)
# OUTPUT: var1 var2 var3 var4
childObject = Child(var4="var4", var1="var1", var3="var3", var2="var2")
print(childObject.var1, childObject.var2, childObject.var3, childObject.var4)
# OUTPUT: var1 var2 var3 var4

Related

Dynamically created instances in python

I have definition of parent class "Parent". I have also defined child classes "child1", "child2". In child's some of the functions are overided some not. But the problem is that number of instances will be defined in .ini file. Question is how to dynamically create this instances. I have tried with "type" but it is not working. Below code with comments
`
class Parent:
def __init__(self, var_1):
self.var_1 = var_1
def method1(self):
print("method1")
def method2(self):
print('method2')
class child1(Parent):
def __init__(self, var_1, var2):
self.var2 = var2
super().init(var_1)
def method2(self):
print('method2_own_implementation')
class child2(Parent):
def __init__(self, var_1, var2):
super().__init__(var_1)
self.var2 = var2
def method1(self):
print("method1_own_implementation")
#4 below lines it is how it normally works
A = child1(2, 'XXX')
A.method2()
B = child2(3, 'sfsaf')
B.method1()
#list_nr define that 2 object of both types should be created, how to do it programmatically?
list_nr = ['child1', 'child1', 'child2', 'child2']
i tried with type, but not working as expected
list_classes = {'child1':child1, 'child2':child2}
created_instances = []
for index, type_obj in enumerate(list_nr):
A = type(('type_obj' + str(index)), (list_classes[type_obj],), {'var_1': 3, 'var2': 'xxx'})
created_instances.append(A)
print(created_instances[0].method1())
after executing this receiving error:
print(created_instances[0].method1()) TypeError: method1() missing 1 required positional argument: 'self'
Not sure if I fully understood your question, but I'm guessing you just want created_instances to contain instance of the classes listed in list_nr with the variable var_1 initialized to 3 and var2 initialized to XXX? If so you are overcomplicating it a bit here is a modified version of your code that does so.
class Parent:
def __init__(self, var_1):
self.var_1 = var_1
def method1(self):
print("method1")
def method2(self):
print('method2')
class child1(Parent):
def __init__(self, var_1, var2):
self.var2 = var2
super().__init__(var_1)
def method2(self):
print('method2_own_implementation')
class child2(Parent):
def __init__(self, var_1, var2):
super().__init__(var_1)
self.var2 = var2
def method1(self):
print("method1_own_implementation")
# 4 below lines it is how it normally works
A = child1(2, 'XXX')
A.method2()
B = child2(3, 'sfsaf')
B.method1()
# list_nr define that 2 object of both types should be created, how to do it programmatically?
list_nr = ['child1', 'child1', 'child2', 'child2']
list_classes = {'child1': child1, 'child2': child2}
created_instances = []
for index, type_obj in enumerate(list_nr):
A = list_classes[type_obj](var_1= 3, var2= 'xxx')
created_instances.append(A)
print(created_instances[0].method1())
The main change I've done is change this line
A = type(('type_obj' + str(index)), (list_classes[type_obj],), {'var_1': 3, 'var2': 'xxx'})
to
A = list_classes[type_obj](var_1= 3, var2= 'xxx')
list_classes[type_obj] is the same thing as the class you want class1 or class2 so it's essentially the same as
A = child1(var_1= 3, var2= 'xxx') # or child2 depending on what type_obj is
Also for some unelicited advice. In the future you might want to reduce the question example to the minimal, reproducable example. For your case your problem had nothing to do with method overloading so you didn't need to include the parent in the example.

Redefining a "subclass" sort of structure using inheritance

I am developing an object oriented application which is very similar to the following limited working example. I am initiating 2 super classes. Class A and class B. Class A defines variables var1 and var2, and contains methods Add, Multiply, Power. Class B defines variables var1 and var2 and contains methods Subtract, Divide and Add.
Class C instantiates an instance of both class A and class B. It then defines a method f1 which utilizes methods from A_obj and B_obj with different names. Notice that method f2 is using the method Add from A_obj and B_obj. The method has the same name but performs a different computation.
The last few lines of the code instantiate an object of class C and then prints out the results using both functions.
class A():
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def Add(self):
result = self.var1 + self.var2
return result
def Multiply(self):
result = self.var1*self.var2
return result
def Power(self):
result = self.var1**self.var2
class B():
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def Subtract(self):
result = self.var1-self.var2
return result
def Divide(self):
result = self.var1/self.var2
return result
def Add(self):
result = self.var1+self.var2+self.var1+self.var2
return result
class C():
def __init__(self, var1, var2, var3, var4):
self.A_obj = A(var1,var2)
self.B_obj = B(var3,var4)
def f1(self):
result = self.A_obj.Add()+self.B_obj.Subtract()
return result
def f2(self):
result = self.A_obj.Add()-self.B_obj.Add()
return result
C_obj = C(1, 2, 3,4)
print(C_obj.f1())
print(C_obj.f2())
My question is, can I achieve this sort of functionality using inheritance? Is inheritance even an appropriate concept to use here? I tried forcing it in a previous question but found out that as soon as you use inheritance variables in subclass C become "globally defined" and are recognized by superclasses A and B. I'd like to make sure everything in class A remains local to A and everything in class B remain local to B.

Calling similar named functions in subclasses from superclass

A follow up from this question, which was not very well formulated. The answer provided some additional insight so now I have constructed a limited working example that explains it better.
Basically we have two subclasses A and B and a class C which inherits from both. Classes A and B both have a function MyFunc but which does different things.
I would like for class C to be able to use both functions and have full control of which function is called since I wish to do different things with each function. The comment in the limited working example below shows what I am trying to do.
class A():
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def MyFunc(self):
result = self.var1 + self.var2
return result
class B():
def __init__(self, var1):
self.var1 = var1
def MyFunc(self):
result = self.var1**2
return result
class C(A,B):
def __init__(self, var1, var2, var3):
A.__init__(self, var1, var2)
B.__init__(self, var3)
def MyFunc(self):
#in this function I want to call MyFunc from A and MyFunc from B. For example to add their results together
How can I call MyFunc in A and MyFunc in B from MyFunc in C?
You can use name mangling to make attributes from a class available in a child class even if that child defines an attribute with the same name.
class A():
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def __MyFunc(self):
result = self.var1 + self.var2
return result
MyFunc = __MyFunc
class B():
def __init__(self, var1):
self.var1 = var1
def __MyFunc(self):
result = self.var1**2
return result
MyFunc = __MyFunc
class C(A,B):
def __init__(self, var1, var2, var3):
A.__init__(self, var1, var2)
B.__init__(self, var3)
def MyFunc(self):
return self._A__MyFunc() + self._B__MyFunc()
c = C(1, 2, 3)
print(c.MyFunc())
# 14
I tried to make the solution look as simple as possible using your example suggestion.
def MyFunc(self):
result = 0
result += A.MyFunc(self=self)
result += B.MyFunc(self=self)
return result

Better way to handle inheritance in constructors

I have the following BaseClass
class A(object):
__metaclass__ = abc.ABCMeta
def __init__(self, val1, val2):
self.v1 = val1
self.v2 = val2
and then some extended class:
class B(A):
def __init__(self, *args, **kwargs):
super(self.__class, self).__init(*args[:len(args)-1], **kwargs
self.v3 = args[len(args)]
basically i want to call it in a way such that:
x = B(1, 2, 34)
but this seems that i need to have a specific order, how do implement init the right way so that the base class can initialize its v1,v2 variables and the extended class B can initialize the v3 value (in this case with 34).
You should be explicit about the required arguments for the super class A.__init__. If you provide < 2 args to B then you would get an error.
class B(A):
def __init__(self, val1, val2, *args):
super(self.__class, self).__init__(val1, val2)
self.v3 = args # or args.pop() or whatever

How would I access variables from one class to another?

I am writing a program that is utilizing multiple classes. I have one class that is dedicated to determining values for a set of variables. I would then like to be able to access the values of those variables with other classes. My code looks as follows:
class ClassA(object):
def __init__(self):
self.var1 = 1
self.var2 = 2
def methodA(self):
self.var1 = self.var1 + self.var2
return self.var1
class ClassB(ClassA):
def __init__(self):
self.var1 = ?
self.var2 = ?
object1 = ClassA()
sum = object1.methodA()
print sum
I use classA to initialize 2 variables (var1 and var2). I then use methodA to add them, saving the result as var1 (I think this will make var1 = 3 and var2 = 2). What I want to know is how would I have ClassB then be able to get the values for var1 and var2 from ClassA?
var1 and var2 are instance variables. That means that you have to send the instance of ClassA to ClassB in order for ClassB to access it, i.e:
class ClassA(object):
def __init__(self):
self.var1 = 1
self.var2 = 2
def methodA(self):
self.var1 = self.var1 + self.var2
return self.var1
class ClassB(ClassA):
def __init__(self, class_a):
self.var1 = class_a.var1
self.var2 = class_a.var2
object1 = ClassA()
sum = object1.methodA()
object2 = ClassB(object1)
print sum
On the other hand - if you were to use class variables, you could access var1 and var2 without sending object1 as a parameter to ClassB.
class ClassA(object):
var1 = 0
var2 = 0
def __init__(self):
ClassA.var1 = 1
ClassA.var2 = 2
def methodA(self):
ClassA.var1 = ClassA.var1 + ClassA.var2
return ClassA.var1
class ClassB(ClassA):
def __init__(self):
print ClassA.var1
print ClassA.var2
object1 = ClassA()
sum = object1.methodA()
object2 = ClassB()
print sum
Note, however, that class variables are shared among all instances of its class.
Can you explain why you want to do this?
You're playing around with instance variables/attributes which won't migrate from one class to another (they're bound not even to ClassA, but to a particular instance of ClassA that you created when you wrote ClassA()). If you want to have changes in one class show up in another, you can use class variables:
class ClassA(object):
var1 = 1
var2 = 2
#classmethod
def method(cls):
cls.var1 = cls.var1 + cls.var2
return cls.var1
In this scenario, ClassB will pick up the values on ClassA from inheritance. You can then access the class variables via ClassA.var1, ClassB.var1 or even from an instance ClassA().var1 (provided that you haven't added an instance method var1 which will be resolved before the class variable in attribute lookup.
I'd have to know a little bit more about your particular use case before I know if this is a course of action that I would actually recommend though...
var1 and var2 is an Instance variables of ClassA. Create an Instance of ClassB and when calling the methodA it will check the methodA in Child class (ClassB) first, If methodA is not present in ClassB you need to invoke the ClassA by using the super() method which will get you all the methods implemented in ClassA. Now, you can access all the methods and attributes of ClassB.
class ClassA(object):
def __init__(self):
self.var1 = 1
self.var2 = 2
def methodA(self):
self.var1 = self.var1 + self.var2
return self.var1
class ClassB(ClassA):
def __init__(self):
super().__init__()
print("var1",self.var1)
print("var2",self.var2)
object1 = ClassB()
sum = object1.methodA()
print(sum)
we can access/pass arguments/variables from one class to another class using object reference.
#Class1
class Test:
def __init__(self):
self.a = 10
self.b = 20
self.add = 0
def calc(self):
self.add = self.a+self.b
#Class 2
class Test2:
def display(self):
print('adding of two numbers: ',self.add)
#creating object for Class1
obj = Test()
#invoking calc method()
obj.calc()
#passing class1 object to class2
Test2.display(obj)
Just create the variables in a class. And then inherit from that class to access its variables. But before accessing them, the parent class has to be called to initiate the variables.
class a:
def func1(self):
a.var1 = "Stack "
class b:
def func2(self):
b.var2 = "Overflow"
class c(a,b):
def func3(self):
c.var3 = a.var1 + b.var2
print(c.var3)
a().func1()
b().func2()
c().func3()
class ClassA(object):
def __init__(self):
self.var1 = 1
self.var2 = 2
def method(self):
self.var1 = self.var1 + self.var2
return self.var1
class ClassB(ClassA):
def __init__(self):
ClassA.__init__(self)
object1 = ClassA()
sum = object1.method()
object2 = ClassB()
print sum

Categories