首页 > 解决方案 > 如何避免python中的并行类层次结构

问题描述

python最近在我的代码中遇到了一种奇怪的小气味,我认为这与并行继承有关。这是我编造的一个小例子:

class DogHabits:
    def __init__(self):
        self.habits = ['lick butt']

class GermanShepherdHabits(DogHabits):
    def __init__(self):
        super().__init__()
        self.habits.extend(['herd sheep'])

class LabradorHabits(DogHabits):
    def __init__(self):
        super().__init__()
        self.habits.extend(['hunt', 'pee on owner'])

class Dog:
    def __init__(self):
        self.type = 'generic_dog'
        self.my_habits = DogHabits()

    def do_stuff(self):
        for habit in self.my_habits.habits:
            print(habit)

class GermanShepherd(Dog):
    def __init__(self):
        self.type = 'german shepherd'
        self.my_habits = GermanShepherdHabits()

class Labrador(Dog):
    def __init__(self):
        self.type = 'labrador'
        self.my_habits = LabradorHabits()

if __name__ == "__main__":
    german_shepherd = GermanShepherd()
    print('\n{}'.format(german_shepherd.type))
    german_shepherd.do_stuff()


    labrador = Labrador()
    print('\n{}'.format(labrador.type))
    labrador.do_stuff()

我有一个通用的狗类,具体的狗实现继承自该类。每个狗类(包括通用/抽象类)都有一组习惯,其本身由习惯的另一个类层次结构表示。

我对我必须始终拥有完全相同的两个层次结构这一事实感到恼火。此外,它们之间的继承在DogHabits习惯层次结构中很有用,但在狗层次结构中没有用,因为我需要为狗层次结构中的每个类实例化一个单独的习惯对象。

这有什么解药?我可能想添加很多狗类的实现,更新相应的习惯层次结构听起来很乏味,而且闻起来很糟糕......

标签: pythonoopdiamond-problem

解决方案


这可能太过分了,但我认为不需要单独的DogHabits课程。habits应该是类属性,而不是实例属性,并且可以由__init_subclass__.

class Dog:
    habits = ['lick butts']

    def __init_subclass__(cls, habits=None, **kwargs):
        super().__init_subclass__(**kwargs)
        if habits is not None:
            cls.habits = cls.habits + habits


class GermanShepherd(Dog, habits=['herd sheep']):
    def __init__(self):
        self.type = 'german shepherd'


class Labrador(Dog, habits=['pee on owner']):
    def __init__(self):
        self.type = 'labrador'

type它本身也更像是类属性而不是实例属性,因为它只是已经由类本身编码的信息的(替代)字符串表示。由于您不会附加到现有值,因此只需在必要时设置类属性而不是通过__init_subclass

class Dog:
    habits = ['lick butts']
    type = 'generic_dog'

    def __init_subclass__(cls, habits=None, **kwargs):
        super().__init_subclass__(**kwargs)
        if habits is not None:
            cls.habits = cls.habits + habits


class GermanShepherd(Dog, habits=['herd sheep']):
    type = 'german shepard'


class Labrador(Dog, habits=['pee on owner']):
    type = 'labrador'


class BlackLabrador(Labrador):
    pass  # E.g. if you are happy with inheriting Labrador.type

推荐阅读