如何避免 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习惯层次结构中很有用,但在狗层次结构中没有用,因为我需要为狗层次结构中的每个类实例化一个单独的习惯对象。


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


小唯快跑啊
浏览 175回答 3
3回答

ITMISS

这可能走得太远了,但我认为不需要单独的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 + habitsclass 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 + habitsclass 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

慕的地8271018

如果习惯需要一个类属性,而不是实例属性,这实际上可能是元类的一个很好的用途。习惯不一定是一个简单的列表,它可以是其他东西,只要有加法和返回新的概念即可。(__add__或者__radd__在习惯课上我认为可以做到这一点)class DogType(type):    def __init__(cls, name, bases, attrs):        """ this is called at the Dog-class creation time.  """        if not bases:            return        #pick the habits of direct ancestor and extend it with         #this class then assign to cls.        if "habits" in attrs:            base_habits = getattr(bases[0], "habits", [])            cls.habits = base_habits + cls.habitsclass Dog(metaclass=DogType):    habits = ["licks butt"]    def __repr__(self):        return f"My name is {self.name}.  I am a {self.__class__.__name__} %s and I like to {self.habits}"    def __init__(self, name):        """ dog instance can have all sorts of instance variables"""        self.name = nameclass Sheperd(Dog):    habits = ["herds sheep"]class GermanSheperd(Sheperd):    habits = ["bites people"]class Poodle(Dog):    habits = ["barks stupidly"]class StBernard(Dog):    passfor ix, cls in enumerate([GermanSheperd, Poodle, StBernard]):    name = f"dog{ix}"    dog = cls(name)    print(dog)输出:My name is dog0.  I am a GermanSheperd %s and I like to ['licks butt', 'herds sheep', 'bites people']My name is dog1.  I am a Poodle %s and I like to ['licks butt', 'barks stupidly']My name is dog2.  I am a StBernard %s and I like to ['licks butt']

白板的微信

这个答案假设 DogHabits 比单纯的列表复杂得多,并且确实值得一个具有自己继承的专用类。从设计的角度来看,我可以看到第一个问题是是否habits以及type应该是类成员还是实例成员。同样,这个答案假设有理由让他们成为实例成员。我会在类文档中创建Habits一个内部类Dogs并声明它可以通过在以下子类中构建它的子类来定制Dogs: class Dog:    class Habits:        """Represents the habits of a Dog.        It can be customized in a child class by creating in the subclass an        inner class named Habits that would be a subclass of Dog.Habits        """        def __init__(self):            self.habits = ['lick butt']    def __init__(self, typ='generic_dog'):        self.type = typ        self.my_habits = self.__class__.Habits()    def do_stuff(self):        for habit in self.my_habits.habits:            print(habit)class GermanShepherd(Dog):    class Habits(Dog.Habits):        def __init__(self):            super().__init__()            self.habits.extend(['herd sheep'])    def __init__(self):        super().__init__('german shepherd')class Labrador(Dog):    class Habits(Dog.Habits):        def __init__(self):            super().__init__()            self.habits.extend(['hunt', 'pee on owner'])    def __init__(self):        super().__init__('labrador')
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python