为了账号安全,请及时绑定邮箱和手机立即绑定

如何避免 python 中的并行类层次结构

如何避免 python 中的并行类层次结构

小唯快跑啊 2022-12-20 16:11:46
我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习惯层次结构中很有用,但在狗层次结构中没有用,因为我需要为狗层次结构中的每个类实例化一个单独的习惯对象。什么是解毒剂?我可能想添加狗类的许多实现,更新相应的习惯层次结构听起来很乏味而且闻起来很糟糕......
查看完整描述

3 回答

?
ITMISS

TA贡献1871条经验 获得超8个赞

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


查看完整回答
反对 回复 2022-12-20
?
慕的地8271018

TA贡献1796条经验 获得超4个赞

如果习惯需要一个类属性,而不是实例属性,这实际上可能是元类的一个很好的用途。


习惯不一定是一个简单的列表,它可以是其他东西,只要有加法和返回新的概念即可。(__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.habits



class 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 = name


class Sheperd(Dog):

    habits = ["herds sheep"]


class GermanSheperd(Sheperd):

    habits = ["bites people"]


class Poodle(Dog):

    habits = ["barks stupidly"]


class StBernard(Dog):

    pass



for 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']


查看完整回答
反对 回复 2022-12-20
?
白板的微信

TA贡献1883条经验 获得超3个赞

这个答案假设 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')


查看完整回答
反对 回复 2022-12-20
  • 3 回答
  • 0 关注
  • 86 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信