use*_*882 3 python oop diamond-problem
我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()
Run Code Online (Sandbox Code Playgroud)
我有一个通用的狗类,具体的狗实现继承自该类。每个狗类(包括通用/抽象类)都有一组习惯,它本身由习惯的另一个类层次结构表示。
令我恼火的是,我必须始终拥有完全相同的两个层次结构。此外, 之间的继承在DogHabits习惯层次结构中很有用,但在狗层次结构中没有用,因为我需要为狗层次结构中的每个类实例化一个单独的习惯对象。
这有什么解药?我可能想添加很多狗类的实现,更新相应的习惯层次听起来很乏味,闻起来很糟糕......
这可能太过分了,但我认为不需要单独的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'
Run Code Online (Sandbox Code Playgroud)
type本身也更像是一个类属性而不是一个实例属性,因为它只是类本身已经编码的信息的(替代)字符串表示。由于您不会附加到现有值,因此只需在必要时设置 class 属性而不是通过__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
Run Code Online (Sandbox Code Playgroud)