Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中的一对多继承_Python_Inheritance_Multiple Inheritance_Diamond Problem - Fatal编程技术网

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,

一个关于我是否以最好的方式做事的问题

我希望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
如果当时我继续使用我最初的方法,并遵循我在使用超类构造函数方面的一贯做法,我显然会两次调用
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()