Reputation: 2250
I am not quite used to class inheritance in Python yet. All I want to do is simply pass all arguments from my base class to the super class when it is created:
class A:
def __init__(self, a, b):
self.a = a
self.b = b
def do(self):
c = self.a + self.b
return B(c=c)
class B(A):
def __init__(self, c):
self.c = c
my_A = A(a=1, b=2)
my_B = my_A.do()
print(my_B.c)
This works as expected. However, what I want is to also be able to call the arguments a
and b
from the x2 instance of the class my_B, so that I can directly write my_B.a
for instance. I know this is done with super() like this:
class A:
def __init__(self, a, b):
self.a = a
self.b = b
def do(self):
c = self.a + self.b
return B(a=self.a, b=self.b, c=c)
class B(A):
def __init__(self, a, b, c):
super(B, self).__init__(a=a, b=b)
self.c = c
my_A = A(a=1, b=2)
my_B = my_A.do()
print(my_B.a)
print(my_B.b)
However, I don't want to explicitly write all arguments of A when I create the instance of B. Is there a way to automatically pass all arguments from class A to class B?
Upvotes: 4
Views: 12335
Reputation: 652
yup there is a way use key word arguments so :
class A(object):
def __init__(self,**kwargs):
# Non pythonic and a bit of a hack
self.kwargs = kwargs
vars(self).update(kwargs)
def do(self):
c = self.a + self.b
return B(c=c, **kwargs)
class B(A):
def __init__(self, c, **kwargs):
self.c = c
super(B, self).__init__(**kwargs)
my_A = A(a=1, b=2)
my_B = my_A.do()
print(my_B.a)
print(my_B.b)
print(my_B.c)
This does what you are after nonethless the way in which it was written before was a bit more pythonic when run this should output:
1
2
3
The downside of doing this is that now A has not limit in terms of the number of attributes but you could ensure this with an assertion or something I guess.
Upvotes: 2
Reputation: 2250
Ok, thanks for your comments. I have come up with this solution:
class A:
def __init__(self, a, b):
self.a = a
self.b = b
def do(self):
c = self.a + self.b
return B(self, c)
class B:
def __init__(self, base, c):
self.base = base
self.c = c
my_A = A(a=1, b=2)
my_B = my_A.do()
print(my_B.base.a)
print(my_B.base.b)
print(my_B.c)
This removes the inheritance of class B and makes the code slightly less readable, but I guess it will do, right? 😊
Upvotes: 2
Reputation: 229361
Based on your comment, you could do something like this:
class B(A):
def __init__(self, c, an_a):
super(B, self).__init__(an_a.a, an_a.b)
self.c = c
You may instead prefer to keep your current constructor and add a from_a
static method:
class B(A):
def __init__(self, c, a, b): # note order
super(B, self).__init__(a=a, b=b)
self.c = c
@staticmethod
def from_a(c, an_a):
return B(c, an_a.a, an_a.b)
Finally, if you don't want to type out all of those parameters, you can add an args()
method to A
and then use the collection unpacking function syntax:
class A:
...
def args(self):
return (self.a, self.b)
class B(A):
def __init__(self, c, *args): # Note *args
super(B, self).__init__(*args)
self.c = c
@staticmethod
def from_a(c, an_a):
return B(c, *an_a.args())
Now B
's constructor takes the parameter special to B
, followed by any number of parameters which just get passed to A
's constructor. This allows you to do the tuple unpacking when calling the constructor, instead of listing everything out manually.
Upvotes: 4