Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
252 views
in Technique[技术] by (71.8m points)

Python: Inheritance versus Composition

I am working with two classes in Python, one of which should be allowed to have any number objects from another class as children while keeping an inventory of these children as an attribute. Inheritance seemed like the obvious choice for this parent<>child situation but instead what I have arrived at is an example of composition. Here is the simplified code:

class Parent:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self.kids = []

    def havechild(self, firstname):
        print(self.firstname, "is having a child")
        self.kids.append(Child(self, firstname))


class Child(Parent):
    def __init__(self, parent, firstname):
        self.parent = parent
        self.firstname = firstname
        self.lastname = parent.lastname

So basically, while it seems to make intuitive sense to have Child() inherit from Parent(), removing the inheritance, does not change anything at all. The only benefit I can see for leaving Child(Parent) instead of just class Child() would be if I needed to add a lot more methods to Parent that I would like Child to inherit. Using the self.parent = parent, I already have access to any additional future attributes of the Parent.

Is there another way to use pure inheritance rather than passing the Parent instance into the Child constructor (composition)?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It is definitely not good to inherint Child from Parent or Parent from Child.

The correct way to do it is to make a base class, let's say Person and inherit both Child and Parent from it. An advantage of doing this is to remove code repetition, at the moment you have only firstname / lastname fields copied into both objects, but you may have more data or additional methods, like get_name() to work with this data.

Here is an example:

class Person:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    def get_name(self):
        return f"{self.firstname} {self.lastname}"


class Parent(Person):
    def __init__(self, firstname, lastname):
        super().__init__(firstname, lastname)
        self.kids = []

    def havechild(self, firstname):
        print(self.firstname, "is having a child")
        self.kids.append(Child(self, firstname))


class Child(Person):
    def __init__(self, parent, firstname):
        super().__init__(firstname, parent.lastname)
        self.parent = parent

Another way of doing this is to do it without inheritance, but only have one Person object (vs Parent and Child). The feature of tracking family status and parents / children can be moved into another object.

An advantage of this approach is that you follow the single responsibility principle and keep objects simple, each object does only one thing.

Here is an example:

from collections import defaultdict


class Person:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    def get_name(self):
        return f"{self.firstname} {self.lastname}"


class FamilyRegistry(object):
    def __init__(self):
        self.kids = defaultdict(list)

    def register_birth(self, parent, child_name):
        print(parent.firstname, "is having a child")
        child = Person(child_name, parent.lastname)
        self.kids[parent.lastname].append(child)
        return child

    def print_children(self, person):
        children = self.kids[person.lastname]
        if len(children) == 0:
            print("{} has no children" % person.get_name())
            return
        for child in children:
            print(child.get_name())

It works like this:

joe = Person('Joe', 'Black')
jill = Person('Jill', 'White')
registry = FamilyRegistry()
registry.register_birth(joe, 'Joe Junior') # Joe is having a child
registry.register_birth(joe, 'Tina')       # Joe is having a child
registry.print_children(joe)               # Joe Junior Black
                                           # Tina Black
registry.print_children(jill)              # Jill White has no children

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...