如何在不带继承属性的情况下添加基于类层次结构的默认值



我有一个类,我们称之为Animal,在一个库中定义。

在一个单独的库中,我想根据它们的子类型用颜色表示这些Animal。例如,Lion对象为红色。 我希望任何Animal都有一个默认颜色,以防颜色不是为其定义的颜色。 我还希望有Animal的子类型,例如Feline,它们本身可以定义默认颜色以取代通用Animals的颜色。

实现此类目标的简单方法如下。(我在这里使用Python来演示,但我认为这是一个与语言无关的问题。

class Animal:
def __init__(self):
self.color = Black
class Feline(Animal):
def __init__(self):
super.__init__()
self.color = Blue
class Dog(Animal):
pass  # self.color == Black
class Cat(Feline):
pass  # self.color == Blue
class Lion(Feline):
def __init__(self):
super.__init__()
self.color = Red

从本质上讲,每个Animal都有一个由自己或定义它的最早祖先定义的color

但是,我不希望Animalcolor是一个字段,即Animal的表示应该与Animal本身分开。

所以,相反,我正在运行更像这样的东西:

# animal.py
class Animal:
pass
class Feline(Animal):
pass
class Dog(Animal):
pass
class Cat(Feline):
pass
class Lion(Feline):
pass

# animal_colors.py
default_colors: dict[type, Color] = {
Animal: Black,
Feline: Blue,
Lion: Red,
# Notice how Cat, and Dog aren't defined here
}
def get_color(animal: Animal, lookup_table:dict[type, Color]=default_colors) -> Color:
mro = type(animal).__mro__
assert Animal in mro, "Non Animal class passed to get_color()"
for t in mro:
try:
return lookup_table[t]
except KeyError:
continue
raise RuntimeError("Animal object has no defined color")

这样get_color(my_animal)将为动物返回所需的颜色。

然而,这对我来说简直是错误的方法......我认为我不应该干涉这样一个简单用例的__mro__。 我正在寻找更好的方法来解决这个问题,即本质上是在类层次结构之外定义属性和默认值。

最后我想提的是,就我的情况而言,拥有AnimalFeline的实例是有意义的,这在传统上是抽象类。 即对象应该能够在层次结构的每个级别实例化。如果需要,也许我可以DefaultAnimalDefaultFeline子类型。

*奖励问题:我相信这种方法违反了利斯霍夫替换原则(如果应该BlueFeline,则不应RedLion)有更好的方法来解决这个问题吗?

听起来您要查找的是类属性。

class Animal:
color = Black
class Feline(Animal):
color = Blue
class Lion(Feline):
color = Red

这定义了属于类本身的属性,而不是属于其实例的属性。它们可以通过实例或类进行访问。例如

Lion.color == Red # attribute on the class object
Lion().color == Red # atteibute on the instance object

Python确实支持抽象类,但它们很少使用。Python是一种高度实用的语言,它避开了Java,C#或C++等强类型OO语言的许多形式。例如,它没有访问修饰符,没有实际信息隐藏,没有接口,并且除了计算属性之外很少使用属性。继承在日常的Python编程中极为罕见。

至于 LSP,您没有违规,至少通常理解主体的方式是这样,因为您可以在 Lion 上访问与猫科动物相同的属性,并获取相同类型的值。LSP 通常被理解为在类型级别而不是值级别运行。

相关内容

最新更新