For example, in the following code, I want to pass 6 parameters by unpacking *num
to initialize a1, a2, a3 in class A and b1, b2, b3 in class B. However, there will be an error because A only has 4 members. How do I pass 6 parameters to initialize A, automatically initialize the first 3 parameters a1, a2, a3, and use the last 3 parameters to initialize b1, b2, b3 in member object b?
The source of the question is because I want to use vars(self)
to extract all member data of the subclass objects of the Base class, just like the get_data method, so that there is no need to display the member names every time, otherwise there will be too much repetitive code, such as return [self.b1, self.b2, self.b3]
, because writing each subclass in this way requires handwritten variable names.
The example code is as follows. When executing A(*num)
, an error message will appear indicating that there are too many parameters
@dataclass
class Base():
def __str__(self):
data = ','.join([str(x) for x in vars(self).values()])
return data
def get_data(self):
return ','.join([str(x) for x in vars(self).values()])
@dataclass
class B(Base):
b1: int = 0
b2: int = 0
b3: int = 0
@dataclass
class A(Base):
a1: int = 0
a2: int = 0
a3: int = 0
b: B = None
num = [1,2,3,4,5,6]
my_data = A(*num)
Initialisation of the member attributes of both A and B can be achieved by having A inherit from B:
from dataclasses import dataclass
@dataclass
class Base:
def __str__(self):
return ",".join(map(str, vars(self).values()))
def __repr__(self):
return ",".join(map(str, vars(self).items()))
@dataclass
class B(Base):
b1: int
b2: int
b3: int
@dataclass
class A(B):
a1: int
a2: int
a3: int
num = [1, 2, 3, 4, 5, 6]
my_data = A(*num)
print(my_data)
print(repr(my_data))
Note that B will be initialised before A.
Output:
1,2,3,4,5,6
A(b1=1, b2=2, b3=3, a1=4, a2=5, a3=6)
Observation:
Do you actually need a dataclass? Using a more "traditional" approach makes your requirement much easier to implement.
In accordance with the requirement to unpack the list when constructing the class, you could do this:
class Base:
def __str__(self):
return ",".join(map(str, vars(self).values()))
def __repr__(self):
return ",".join(map(str, vars(self).items()))
class B(Base):
def __init__(self, *args):
self.b1, self.b2, self.b3 = args
class A(B):
def __init__(self, *args):
self.a1, self.a2, self.a3 = args[:3]
super().__init__(*args[3:])
data = [1,2,3,4,5,6]
print(A(*data))
print(repr(A(*data)))
Output:
1,2,3,4,5,6
('a1', 1),('a2', 2),('a3', 3),('b1', 4),('b2', 5),('b3', 6)
In this case A is initialised before B.
Taking matters a step further where there's a more complex subclassing pattern then:
class Base:
def __str__(self):
return ",".join(map(str, vars(self).values()))
def __repr__(self):
return ",".join(map(str, vars(self).items()))
class C(Base):
def __init__(self, *args):
self.c1, self.c2, self.c3 = args[:3]
class B(C):
def __init__(self, *args):
self.b1, self.b2, self.b3 = args[:3]
super().__init__(*args[3:])
class A(B):
def __init__(self, *args):
self.a1, self.a2, self.a3 = args[:3]
super().__init__(*args[3:])
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(A(*data))
print(repr(A(*data)))
Output:
1,2,3,4,5,6,7,8,9
('a1', 1),('a2', 2),('a3', 3),('b1', 4),('b2', 5),('b3', 6),('c1', 7),('c2', 8),('c3', 9)