Python中的一对多继承
一个关于我是否以最好的方式做事的问题 我希望Python中的类层次结构(至少)如下所示:Python中的一对多继承,python,inheritance,multiple-inheritance,diamond-problem,Python,Inheritance,Multiple Inheritance,Diamond Problem,一个关于我是否以最好的方式做事的问题 我希望Python中的类层次结构(至少)如下所示: class Actor class Mover(Actor) class Attacker(Actor) class Human(Mover, Attacker) 但是我遇到了这样一个事实,Actor有一个特定的属性,我想从每个Mover和Attacker子类中初始化它,如下面所示 class Actor: _world = None def __init__(self,
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
如果当时我继续使用我最初的方法,并遵循我在使用超类构造函数方面的一贯做法,我显然会两次调用Actor
构造函数——这不是问题,但我的程序员感觉到刺痛,并说我宁愿用更干净的方式来做
class Human(Mover, Attacker):
def __init__(self, world, speed, range):
Mover.__init__(self, world, speed)
Attacker.__init__(self, world, range)
例如,我只能调用移动器
构造函数,并简单地显式初始化人类
的\u范围
,但这是一种更糟糕的方法,因为它为攻击者
复制了初始化代码
正如我所说,我知道设置两次
\u world
属性并没有什么大不了的,但是您可以想象,如果在Actor.\uuuuu init\uuuu
中进行了更密集的操作,这种情况将令人担忧。有谁能推荐一种更好的在Python中实现这种结构的方法吗?这里的内容叫做。Python对象模型通过使用;实际上,您所要做的就是使用super
并通过**kwargs
(在Python 2中,从对象
继承):
请注意,您现在需要使用kwargs样式构建Human
:
human = Human(world=world, range=range, speed=speed)
这里到底发生了什么?如果插入\uuuu init\uuuu
调用,您会发现(为了简洁起见,将类重命名为A、B、C、D
):
调用D.\uuuu init\uuuu
B.\uuuuu init\uuuu
调用B.uuu init_uuu
C.uuu init_uu
调用C.\uuuu init\uuuu
A.\uuuu init\uuuu
调用A.。\uuuu init\uuuu
对象。\uuuuu init\uuuu
D
实例的super(B,self)
知道C
是方法解析顺序中的下一个,因此它转到C
,而不是直接转到A
。我们可以通过查看MRO进行检查:
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
您不会两次调用构造函数(最好说是“初始值设定项”)。继承不是这样的。您最好看一下MRO主题,为自己澄清Python继承:非常感谢您的回答!我一直有点困惑,比如说,
super(self,Human)。\uuu init\uuuuu
在Human
初始化器中指的是什么-这本质上是说‘我将把所有这些命名的参数都给Human
的初始化器,’,MRO需要向上看,找出哪个Human
超类可以处理这些参数?我想如果我知道它被称为钻石继承,我可能会在发布之前找到一些答案-我确实尝试过,老实说!)啊,对你的答案和所有内容的有用编辑;如果我能投更多的票,我会的,先生。这就把事情弄清楚了——我一直在读@RostyslavDzinko在上面发表的文章,我正在学习线性化——这开始变得有意义了:)@不知不觉,比这简单多了;它的意思是“查看self
的MRO,沿着它走,直到我找到Human
,并在Human
之后直接调用类上的方法”。
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
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()