How can I call a particular base class method in Python? - python

Let's say, I have the following two classes:
class A(object):
def __init__(self, i):
self.i = i
class B(object):
def __init__(self, j):
self.j = j
class C(A, B):
def __init__(self):
super(C, self).__init__(self, 4)
c = C()
c will only have the i attribute set, not the j.
What should I write to set both of attributes/only the j attribute?

If you want to set only the j attribute, then only call B.__init__:
class C(A, B):
def __init__(self):
B.__init__(self,4)
If you want to manually call both A and B's __init__ methods, then
of course you could do this:
class C(A, B):
def __init__(self):
A.__init__(self,4)
B.__init__(self,4)
Using super is a bit tricky (in particular, see the section entitled "Argument passing, argh!"). If you still want to use super, here is one way you could do it:
class D(object):
def __init__(self, i):
pass
class A(D):
def __init__(self, i):
super(A,self).__init__(i)
self.i = i
class B(D):
def __init__(self, j):
super(B,self).__init__(j)
self.j = j
class C(A, B):
def __init__(self):
super(C, self).__init__(4)
c = C()
print(c.i,c.j)
# (4, 4)

Related

python class B inherit class A with all its methods but change one method only

Let's say class A has 10 methods. Some of the methods are private and it has private attributes as well. I want to create class B so I can change last method only without duplicating the code for the rest of the methods. My example is below. At the moment I am unable to achieve it with such inheritance as I get AttributeError: 'B' object has no attribute '_B__c'
class A:
def __init__(self, a=1, b=2):
self.a = a
self.b = b
self.__foo()
def __foo(self):
self.__c = self.a + self.b
def get_data(self):
return self.__c
class B(A):
def __init__(self, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
self.__c = self.__modify_data()
def __modify_data(self):
self.__c += 10000
def get_data(self):
return self.__c
b = B(a=5, b=10).get_data()
Question 2:
Can I achieve it with use of *args so I do not have to repeat all the arguments?
EDIT:
Please see my updated code above.
I believe private attributes causes the problem.
Can I solve it with still using private?
class A(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
self.__foo()
def __foo(self):
self._c = self.a + self.b
def get_data(self):
return self._c
class B(A):
def __init__(self, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
self.__modify_data()
def __modify_data(self):
self._c += 10000
b = B(a=5, b=10).get_data()
print(b)
Output:
10015
Changing _c to __c gives AttributeError: 'B' object has no attribute '_B__c'
Yes, the __ is causing the trouble by making variable c inaccessible in children, which is good because the private variable of parents should not be allowed to edit by the children class.

Python Inheritence Subclass(ing)

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

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?

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