Python Inheritence Subclass(ing) - python

Given a parent class 'A'
class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
def methodA():
# do something
What is the difference between making a subclass 'B' among the below options
Option 1
class B(A):
def methodB():
# do something
Option 2
class B(A):
def __init__(self,a,b):
A.__init__(self, a, b)
def methodB():
# do something

class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
class B(A):
def __init__(self,a,b):
A.__init__(self, a, b)
def methodB():
pass
class C(A):
def methodB():
pass
b = B(1,2)
c = C(1,2)
print b.a == c.a # True
print b.b == c.b # True
In both class instantiation, init under class A will be ran only once.
so no, there is nothing significantly different.
class B is not clean IMO and poses no real purpose at all. It will be ran anyways.
If you wish to do something different in class B init, then yes, you can use this code.
class B(A):
def __init__(self,a,b):
A.__init__(self, a+1, b+1)
def methodB():
pass

Related

Inherit from a "sibling" class?

Imagine I have:
class ABC():
def main(self, x):
self.x = x
class A(ABC):
def afunction(self):
self.a = 2
class B(ABC):
def bfunction(self):
self.b = self.a * self.x
return self.b
How is it possible that class B inherits the self.a and self.x from class A and ABC? (I do not care about inheriting the methods)
If I understand correctly, what you want is to get B to inherit from A.
Notice that what will happen is that it will inherit A variables, and because A inherits from ABC, B will inherit ABC's variables as well.
Also, please note that you will have to initialize the x variable for example inside an B object in order to use the bFunction, and in general it is proper coding to set a constructor as follows:
class ABC():
def __init__(self, x=0):
self.x = x
def main(self, x):
self.x = x
class A(ABC):
def __init__(self, a=2):
super().__init__()
self.a = a
def afunction(self):
self.a = 2
class B(A):
def __init__(self, b=0):
super().__init__()
self.b = b
def bfunction(self):
self.b = self.a * self.x
return self.b
b = B()
b.main(3)
b.afunction()
print(b.bfunction())
Output:
6
If B inherits from A, which inherits from ABC, then B will have ABC and A's methods but neither the 'x' or 'a' attributes which are only set after the methods are run. This works if you rewrite B as:
class B(A):
def bfunction(self, x):
self.main(x)
self.afunction()
self.b = self.a * self.x
return self.b
b = B()
print(b.bfunction(10))
You have to supply 'x' to b.bfunction so that self.b = self.a * self.x works.

Super with arguments in case of multiple inheritance

I have a class that inherits from two other classes whose __init__ take both a parameter like this:
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
super(C, self).__init__(a, b)
c = ClassC(1, 2)
This gives a TypeError: __init__() takes exactly 2 arguments (3 given).
When setting b in B to a fixed value and passing only 1 parameter to super then trying to access b in C gives an AttributeError: 'ClassC' object has no attribute 'b':
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, b):
self.b = 2
class C(A, B):
def __init__(self, a, b):
super(C, self).__init__(a)
print self.a
print self.b
c = ClassC(1, 2)
When calling the __init__ manually everything seems to be fine:
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
A.__init__(a)
B.__init__(b)
print self.a
print self.b
c = ClassC(1, 2)
So how can I get this inheritance straight and how can I manage the parameters for __init__ of inherited classes when using super? Is it even possible? How does super know which parameters are to pass to which class?

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 classes dependant on eachother, how to init?

I have two classes:
class A(object):
def __init__(self, b):
self b = b
class B(object):
def __init__(self, a):
self a = a
I'd like to init them like this:
a = A(b)
b = B(a)
But I can't since 'b' doesn't exist when doing a = A(b). I have to do:
a = A()
b = B(a)
b.a = a
But that seems unclean. Is this solvable?
You could either make one class instantiate the other:
class A(object):
def __init__(self):
self.b = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
b = a.b
Or make one class tell the other about itself, like this:
class A(object):
def __init__(self, b):
self.b = b
b.a = self
class B(object):
def __init__(self):
#Will be set by A later
self.a = None
b = B()
a = A(b)

Multiple inheritance problem in Python!

Why does c.print_a() output 'B'?
class A(object):
def __init__(self):
self.some_name = 'A'
def print_a(self):
print self.some_name
class B(object):
def __init__(self):
self.some_name = 'B'
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
if __name__ == '__main__':
c = C()
c.print_a()
class A(object):
def __init__(self, some_name='A'):
self.some_name = some_name
def print_a(self):
print self.some_name
class B(object):
def __init__(self, some_name='B'):
self.some_name = some_name
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
A.__init__(self, some_name='AAAAA')
B.__init__(self, some_name='BBBBB')
if __name__ == '__main__':
c = C()
c.print_a()
You only have a single object here; the some_name property is shared between methods from all inherited classes. You call A.__init__, which sets it to A, then B.__init__, which changes it to B.
Also note that you're calling base methods incorrectly; use super:
class A(object):
def __init__(self):
self.some_name = 'A'
super(A, self).__init__()
def print_a(self):
print self.some_name
class B(object):
def __init__(self):
self.some_name = 'B'
super(B, self).__init__()
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
super(C, self).__init__()
if __name__ == '__main__':
c = C()
c.print_a()
There's only one self, and you're overwriting its some_name in B.__init__. Maybe you're used to C++, where there would be two separate fields, A.some_name and B.some_name. This concept doesn't apply to Python, where attributes are created dynamically on assignment.
Say you want C to set names for some objects of types A and B and later calling some print_a and print_b methods on objects of type C get these names back ?
You can get this type of behavior using C++ inheritance model, but python model is very different. Only one object with one set of fields. If you want the C++ behavior, the simplest way is probably to declare subobjects (and it looks like a common abuse of inheritance over composition).
Looks like you are trying to do something like below:
class Printable(object):
def __init__(self, name):
self.name = name
def myprint(self):
print self.name
class C(object):
def __init__(self):
self.a = Printable('A')
self.b = Printable('B')
def print_a(self):
self.a.myprint()
def print_b(self):
self.a.myprint()
if __name__ == '__main__':
c = C()
c.print_a()

Categories