Python中的一对多继承
作者:互联网
关于我是否以最佳方式进行某事的问题……
我希望在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构造函数两次 – 不是问题,但我的程序员感觉到了tingles并说我宁愿做得更干净;
class Human(Mover, Attacker):
def __init__(self, world, speed, range):
Mover.__init__(self, world, speed)
Attacker.__init__(self, world, range)
例如,我只能调用Mover构造函数,只是简单地初始化了Human的_range,但这对我来说是一个更糟糕的方法,因为它复制了攻击者的初始化代码.
就像我说的那样,我知道两次设置_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__
发生的事情是,在D的实例上调用的super(B,self)知道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!
请注意,超级绝对不是魔术;它的作用可以用Python本身近似(这里仅用于super(cls,obj)功能,使用闭包来绕过__getattribute__ circularity):
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()
标签:diamond-problem,python,inheritance,multiple-inheritance 来源: https://codeday.me/bug/20190901/1786608.html