How to access variables from inherited class of parent in python? - python

I have the following code , where I want to achieve the following:
Please Understand I am a newbie in OOP
1) Initialize "class B" from main function
2) Inherit "class A" from "class B" and depending upon some conditions of variables of "class A" call "class D" from within "class B"
3) After call of "class D" use variables from "class A" to modify them and print it out.
4) After that go back to "class B" to run code for more conditions.
```
class A(object):
def __init__(self):
super(A,self).__init__()
self.A_var = 0
print('Running A.__init__')
class B(A):
def __init__(self):
super(B,self).__init__()
#B.__init__(self)
def fun2():
self.A_var += 5
#foo = D()
self.fun1
print('Running B.__init__')
print self.A_var
#A.__init__(self)
class D(B,A):
def __init__(self):
#super(A,grandfather).__init__()
#A.__init__(grandfather)
super(D,self).__init__()
#D.__init__(self)
def fun1():
print('Running D.__init__')
self.A_var += 400
print self.A_var
if __name__ == '__main__':
b = B()
b.fun2
```
I want to print out the value of "self.A_var" from inside "class D"

if you want to print out the value of "self.A_var" from inside "class D"
than execute : d.fun1()
checkout this modified code:
class A(object):
def __init__(self):
super(A, self).__init__()
self.A_var = 0
print('Running A.__init__')
class B(A):
def __init__(self):
super(B, self).__init__()
def fun2(self):
self.A_var += 5
print ('Running B.__init__'), self.A_var
class D(B):
def __init__(self):
super(D, self).__init__()
def fun1(self):
self.A_var += 400
print ('Running D.__init__'), self.A_var
if __name__ == '__main__':
d = D()
d.fun2()
d.fun1()
with this code output is
Running A.__init__
Running B.__init__ 5
Running D.__init__ 405

You haven't understood what inheritance is. An instance of D is an instance of A and B, because it inherits from them. The only thing you need to do is make sure you call super() in each __init__ method; for some reason you've replaced the one in D with the totally wrong D.__init__, which will endlessly recurse. Put back super(D,self).__init__().
The only other change is to remove the pointless instantiation of D within B.fun2; just call self.fun1() there.

Related

Share attributes/ variables between classes python

class Base(object):
def __init__(self):
print("Base created")
a = "baseclass"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
b = "child a"
class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
c = "child b"
print(a)
print(b)
ChildA()
ChildB()
NameError: name 'a' is not defined
Your issue here is that you're trying to access local variables instead of instance attributes.
Here's how you should do it:
class Base():
def __init__(self):
print("Base created")
# Note that you should use `self.a` instead of `a`
self.a = "baseclass"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
# Use `self.b` instead of `b`
self.b = "child a"
# Did you forget to inherit from `ChildA`?
class ChildB(ChildA):
def __init__(self):
# The `super()` call can be simplified
super().__init__()
# Use `self.c` instead of `c'
self.c = "child b"
# Access the instance variables using `self.`
print(self.c)
print(self.b)
print(self.a)
ChildA()
ChildB()
From the console output:
Base created
Base created
child b
child a
baseclass

What is happening here in Python with OOPs while trying Diamond Shape problem

I am learning OOPs with python. created below code to replicate the diamond shape problem in multiple inheritence. I am running the below code in jupyter notebook and output is generated at same.
class parent:
def __init__(self):
self.a=2
self.b=4
def form1(self):
print("calling parent from1")
print('p',self.a+self.b)
class child1(parent):
def __init__(self):
self.a=50
self.b=4
def form1(self):
print('bye',self.a-self.b)
def callchildform1(self):
print("calling parent from child1")
super().form1()
class child2(parent):
def __init__(self):
self.a=3
self.b=4
def form1(self):
print('hi',self.a*self.b)
def callchildform1(self):
print("calling parent from child2")
super().form1()
class grandchild(child1,child2):
def __init__(self):
self.a=10
self.b=4
def callingparent(self):
super().form1()
g=grandchild()
g.form1()
g.callchildform1()
g.callingparent()
The output is below
bye 6
calling parent from child1
hi 40
bye 6
I can understand the "bye 6" output both the times but how it is printing "hi 40". I am new so anybody can explain what is happening here.
You may find the __mro__ attribute of a class informative. Here, MRO stands for Method Resolution Order.
Consider this modification to your code:
class Parent:
def __init__(self):
self.a = 2
self.b = 4
def print_name(self):
print("parent")
def form1(self):
print("calling parent form1")
print('p', self.a + self.b)
class Child1(Parent):
def __init__(self):
self.a = 50
self.b = 4
def print_name(self):
print("child1")
def print_super_name(self):
super().print_name()
def form1(self):
print('bye', self.a - self.b)
def callchildform1(self):
print("calling parent from child1")
super().form1()
class Child2(Parent):
def __init__(self):
self.a = 3
self.b = 4
def print_name(self):
print("child2")
def form1(self):
print('hi', self.a * self.b)
def callchildform1(self):
print("calling parent from child2")
super().form1()
class Grandchild(Child1, Child2):
def __init__(self):
self.a = 10
self.b = 4
def print_name(self):
print("grandchild")
def print_super_name(self):
super().print_name()
def print_super_super_name(self):
super().print_super_name()
def callingparent(self):
super().form1()
g = Grandchild()
print("When I print the name of my class it is:")
g.print_name()
print("When I print my superclass name, it is:")
g.print_super_name()
print("When I print the name of the superclass of my superclass, it is:")
g.print_super_super_name()
print("When you call methods on me, they will be executed from my class and my parent classes in the following order:")
print(Grandchild.__mro__)
g.form1()
g.callchildform1()
g.callingparent()
The output is:
When I print the name of my class it is:
grandchild
When I print my superclass name, it is:
child1
When I print the name of the superclass of my superclass, it is:
child2
When you call methods on me, they will be executed from my class and my parent classes in the following order:
(<class '__main__.Grandchild'>, <class '__main__.Child1'>, <class '__main__.Child2'>, <class '__main__.Parent'>, <class 'object'>)
bye 6
calling parent from child1
hi 40
bye 6
When you run g.callchildform1() Python looks for the definition of callchildform1 in Grandchild. It isn't there, so the next place it looks is Child1. You can see from the example and from the method resolution order that when an instance of Grandchild calls a method defined in Child1 which calls super(), the search for the called method will begin in Child2.

Using super within nested class

I am puzzled with the following error in python 2.7.12
Suppose we have a class definition within a class, something similar to this:
class C(object):
def __init__(self):
print "class C"
class D(object):
def __init__(self):
print "class D"
class A(D):
class B(C):
def __init__(self):
# Strangely here B is "not defined", why?
super(B, self).__init__()
print "class B"
def __init__(self):
super(D, self).__init__()
print "class A"
def do_something(self):
b_class = self.B()
print "b_class within A : {}".format(b_class)
a_class = A()
a_class.do_something()
but if we we extract the definition of class B outside the scope of class A,
everything works well.
Do we need to use "super" differently when called within a nested class? I fail to understand why its usage would be different within or outside the nested class. Any pointers?
The problem is not the subclass or superclass, but the nesting. B itself is not defined, only A.B is.
Note that in Python there is almost never a good reason to nest classes, though.
You need to address B by its full name, A.B:
class C(object):
def __init__(self):
print "class C"
class D(object):
def __init__(self):
print "class D"
class A(D):
class B(C):
def __init__(self):
super(A.B, self).__init__()
print "class B"
def __init__(self):
super(D, self).__init__()
print "class A"
def do_something(self):
b_class = self.B()
print "b_class within A : {}".format(b_class)
>>> a_class = A()
>>> a_class.do_something()
class A
class C
class B
b_class within A : <__main__.B object at 0x7f0cac98cbd0>

Regarding python MRO and how super() behaves

Today i was trying to figure out how __mro__ and super works in python, I found something interesting as well as strange to me, because I got something which is not that i understood after reading __mro__. Here is the code snippets.
Code Snippets 1:
#!/usr/bin/pyhon
class A(object):
def test(self):
return 'A'
class B(A):
def test(self):
return 'B to %s' % super(B, self).test()
class C(A):
def test(self):
return 'C'
class D(B, C):
pass
print D().test()
Output :
B to C
Code snippet 2: When I update my super inside class B:
#!/usr/bin/pyhon
class A(object):
def test(self):
return 'A'
class B(A):
def test(self):
return 'B to %s' % super(C, self).test()
class C(A):
def test(self):
return 'C'
class D(B, C):
pass
print D().test()
Output:
B to A
Then now i got what I expected before. Could someone please explain how mro works with super ?
The MRO for D is [D, B, C, A, object].
super(C, self) ~ A
super(B, self) ~ C
super(MyClass, self) is not about the "base class of MyClass", but about the next class in the MRO list of MyClass.
As stated in the comments, super(…) actually does not return the next class in the MRO, but delegates calls to it.

Python - Accessing parent members

I'm facing a standstill here while trying to figure out how to have member classes access data from their parent when they are part of an external module.
Basically, this works (the B class can access is parent's methods like so: A.say_hi(A) ):
class A:
def __init__(self):
print("Initializing parent object...")
self.child = self.B()
class B:
def __init__(self):
print("Initializing child...")
A.say_hi(A)
def say_hi(self):
print("A class says hi")
However, this can get pretty messy if classes start getting extra large, so I have been placing my additional classes in files and importing them inline. The problem with that is I can no longer get the member class to access its parent's members and functions if I try to use 'import B.py' when class B is defined within.
Is there any way to get the original behavior without leaving the member class inside the same file as the parent?
Actually in your example you couldn't access instance of A in your class B. And the code A.say_hi(A) does work however is wrong. This has been said in comments to your question.
Here is how you do that if you want to be able to access parent instance:
Module b:
class B(object):
def __init__(self, parent):
self.parent = parent
def say_hi(self):
print 'Child says hi to his parent %s' % (
self.parent.__class__.__name__
)
self.parent.say_hi()
Module a:
from b import B
class A(object):
def __init__(self):
self.b = B(self)
def say_hi(self):
print 'Parent says hi!'
If you pass the object (a) to the class (b), you can call it directly.
class a():
def __init__(self):
print"Made A"
def test(self):
print ">>A Test"
class b():
def __init__(self,parent):
print"Made B"
self.parent = parent
def test(self):
print ">>B Test"
self.parent.test()
a = a()
a.test()
b = b(a)
b.test()

Categories