Python:继承与组合

Arn*_*rne 12 python inheritance composition

我正在使用Python中的两个类,其中一个应该被允许将来自另一个类的任何数字对象作为子项,同时将这些子项的清单作为属性保留.继承似乎是这个父<>孩子情况的明显选择,而是我所得到的是一个组合的例子.这是简化的代码:


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
Run Code Online (Sandbox Code Playgroud)

所以基本上,虽然从Child()继承Child()似乎直觉上有意义,但删除继承并不会改变任何东西.我可以看到离开Child(Parent)而不仅仅是类Child()的唯一好处是,如果我需要向Parent添加更多方法,我希望Child继承.使用self.parent = parent,我已经可以访问Parent的任何其他未来属性.

有没有其他方法可以使用纯继承而不是将Parent实例传递给Child构造函数(组合)?

Bor*_*rov 23

从父母或父母继承孩子是绝对不好的.

正确的方法是创建一个基类,让我们说Person,并从中继承Child和Parent.执行此操作的一个优点是删除代码重复,此时您只将firstname/lastname字段复制到两个对象中,但您可能有更多数据或其他方法,例如get_name()使用此数据.

这是一个例子:

class Person(object):

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

    def get_name(self):
        return '%s %s' % (self.firstname, self.lastname)


class Parent(Person):

    def __init__(self, firstname, lastname):
        super(Parent, self).__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(Child, self).__init__(firstname, parent.lastname)
        self.parent = parent
Run Code Online (Sandbox Code Playgroud)

另一种方法是在没有继承的情况下执行此操作,但只有一个Person对象(vs Parent和Child).跟踪家庭状态和父母/孩子的功能可以移动到另一个对象.

这种方法的一个优点是您遵循单一责任原则并保持对象简单,每个对象只做一件事.

这是一个例子:

from collections import defaultdict

class Person(object):

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

    def get_name(self):
        return '%s %s' % (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 '%s has no children' % person.get_name()
            return
        for child in children:
            print child.get_name()
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:

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
Run Code Online (Sandbox Code Playgroud)