关于我是否以最好的方式去做某事的问题...
我希望在 Python 中有一个类层次结构(至少)如下所示;
class Actor
class Mover(Actor)
class Attacker(Actor)
class Human(Mover, Attacker)
但是我遇到了这样一个事实,即 Actor
有一个我想初始化的特定属性,来自每个 Mover
和 Attacker
子类,如下所示;
class Actor:
_world = None
def __init__(self, world):
self._world = world
class Mover(Actor):
_speed = 0
def __init__(self, world, speed):
Actor.__init__(self, world)
self._speed = speed
class Attacker(Actor):
_range = 0
def __init__(self, world, range):
Actor.__init__(self, world)
self._range = range
如果我当时采用我最初的方法,并遵循我在使用父类(super class)构造函数方面的一贯做法,我显然最终会调用 Actor
构造函数两次 - 而不是问题,但我的程序员感到刺痛并说我宁愿用更干净的方式来做;
class Human(Mover, Attacker):
def __init__(self, world, speed, range):
Mover.__init__(self, world, speed)
Attacker.__init__(self, world, range)
例如,我可以只调用Mover
构造函数,并简单地初始化Human
的_range
明确地,但这让我觉得这是一种远更糟糕的方法,因为它复制了 Attacker
的初始化代码。
正如我所说,我知道将 _world
属性设置两次没什么大不了的,但是您可以想象,如果在 Actor.__init__
中进行了更密集的操作>,这种情况会令人担忧。有人可以建议在 Python 中实现此结构的更好做法吗?
最佳答案
你在这里得到的是diamond inheritance . Python 对象模型通过 method resolution order 解决了这个问题算法,它使用 C3 linearization ;实际上,您所要做的就是使用 super
并通过 **kwargs
(在 Python 2 中,继承自 object
):
class Actor(object): # in Python 3, class Actor:
_world = None
def __init__(self, world):
self._world = world
class Mover(Actor):
_speed = 0
def __init__(self, speed, **kwargs):
super(Mover, self).__init__(**kwargs) # in Python 3, super().__init__(**kwargs)
self._speed = speed
class Attacker(Actor):
_range = 0
def __init__(self, range, **kwargs):
super(Attacker, self).__init__(**kwargs) # in Python 3, super().__init__(**kwargs)
self._range = range
class Human(Mover, Attacker):
def __init__(self, **kwargs):
super(Human, self).__init__(**kwargs) # in Python 3, super().__init__(**kwargs)
请注意,您现在需要使用 kwargs 样式构造 Human
:
human = Human(world=world, range=range, speed=speed)
这里究竟发生了什么?如果检测 __init__
调用,您会发现(为简洁起见,将类重命名为 A、B、C、D
):
D.__init__
调用B.__init__
B.__init__
调用C.__init__
C.__init__
调用A.__init__
A.__init__
调用object.__init__
发生的事情是 super(B, self)
调用 D
的实例知道 C
在方法解析顺序中是下一个, 所以它转到 C
而不是直接转到 A
。我们可以通过查看 MRO 来检查:
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
为了更好地理解,请阅读 Python’s super() considered super!
请注意 super
绝对不是魔法;它所做的可以在 Python 本身中进行近似(此处仅针对 super(cls, obj)
功能,使用闭包绕过 __getattribute__
循环性):
def super(cls, obj):
mro = type(obj).__mro__
parent = mro[mro.index(cls) + 1]
class proxy(object):
def __getattribute__(self, name):
return getattr(parent, name).__get__(obj)
return proxy()
关于python - Python中的一对一继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11932013/