MoneyBall
MoneyBall

Reputation: 2563

How to instantiate a child class from parent class

I want to create a child class from a parent class. This is to reduce redundancy in code. For instance,

class Parent():
   def __init__(self, a, b, c, d, e, f, g):
       self.a = a
       self.b = b
       ...
       self.g = g

class Child1(Parent):
   def __init__(self, a, b, c, d, e, f, g, h, i, j, k):
          super().__init__(a, b, c d, e, f, g)
          self.i = i
          self.j = j
          self.k = k

class Child2(Parent):
   def __init__(self, a, b, c, d, e, f, g, h, x, y, z):
          super().__init__(a, b, c d, e, f, g)
          self.x = x
          self.y = y
          self.z = z

I don't want to pass parameters again and again for all child classes. Is there a way I could make Child1 and Child2 from Parent class?

I have 30+ parameters and many child classes. It seems very redundant to write out all parameters. Plus, they all share the same parameters as parents.

Upvotes: 3

Views: 10098

Answers (3)

abarnert
abarnert

Reputation: 365617

What you're looking to do here has nothing to do with instantiation. That word means to create an instance of a class. You can't "instantiate a child class from parent class", because a class object is not (except in very unusual circumstances) an instance of its base class.

What you're trying to do is to eliminate some boilerplate.

Python is very flexible—instances can define attributes wherever they want, classes can have any signature they want for methods like __init__ and __repr__, etc. This is very powerful, but it also means that when you have a very repetitive class hierarchy, you have to repeat yourself a lot. But—because Python is very flexible—you can write tools to generate all that repetitive stuff for you, or you can just use tools that come with the language, like @dataclass:1

from dataclasses import dataclass

@dataclass
class Parent:
    a: int
    b: int
    c: int
    d: int
    e: int
    f: int
    g: int
    h: int

@dataclass
class Child1(Parent):
    i: int
    j: int
    k: int

@dataclass
class Child2(Parent):
    x: int
    y: int
    z: int

That's all it takes to define your classes, including automatically generating __init__ methods that can handle both positional and keyword arguments and forward the right things to base classes, and __repr__ methods that display things in some useful way, and static type hints that Mypy can check for you, and so on, without any repetition:

>>> c1 = Child1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
>>> c1
Child1(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10, k=11)
>>> c1b = Child1(1, 2, 3, 4, 5, 6, 7, k=11, j=10, h=8, i=9)
>>> c1 == c1b
True
>>> c2 = Child2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
>>> c1 == c2
False

If you read the docs, you'll see that there's a lot more flexibility there (and even more in attrs), but the defaults give you what you want 80% of the time.


@dataclass was added in Python 3.7. There's a backport for 3.6 that you can install with just pip install dataclasses, but if you need to work with 3.5 or 2.7, you'll need a third-party library like attrs instead. Also look at namedtuple for very simple cases, which works all the way back to 2.6 and 3.1.

Upvotes: 4

mhawke
mhawke

Reputation: 87054

It's not clear from your example whether inheritance is appropriate here. Does the child satisfy the is a relationship, i.e., is the child really a subclass of the parent? If it does not then you should consider using composition rather than inheritance.

I suggest composition because you mention, in a comment, instantiating the parent class and using that instance in the "child" classes. So you could create an instance of the parent and pass it to __init__() of the "child" classes, thereby using composition.

class Parent():
   def __init__(self, a, b, c, d, e, f, g):
       self.a = a
       self.b = b
       ...
       self.g = g

class Child1:
    def __init__(self, parent, h, i, j, k):
        self.parent = parent
        self.h = h
        self.i = i
        self.j = j
        self.k = k

Within the child classes you would access parent attributes via self.parent.a for example.

Upvotes: 3

DYZ
DYZ

Reputation: 57033

You can pass all parameters to the subclass's __init__ as a list, pass as many as necessary to the superclass, and use the rest in the subclass itself:

class Parent():
    def __init__(self,a,b,c):
        print(a,b,c)

class Child1(Parent):
    def __init__(self, *args):
        super().__init__(*args[:3]) # 3 for the parent
        self.x, self.y = args[3:] # 2 for myself
        print(self.x, self.y)

Child1(1,2,3,4,5)
#1 2 3
#4 5
#<__main__.Child1 object at 0x7f5d70c3c9e8>

Upvotes: 0

Related Questions