unw*_*ing 3 python inheritance multiple-inheritance diamond-problem
关于我是否以最佳方式进行某事的问题......
我希望在Python中有一个类层次结构,它看起来(最低限度)如下所示;
class Actor
class Mover(Actor)
class Attacker(Actor)
class Human(Mover, Attacker)
Run Code Online (Sandbox Code Playgroud)
但我反对的事实跑起来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
Run Code Online (Sandbox Code Playgroud)
如果我当时采用我的初始方法,并遵循我在使用超类'构造函数方面的常规方法,我显然最终会调用Actor
构造函数两次 - 不是问题,但我的程序员感觉到了刺痛并说我'而宁愿做一个更干净的方式;
class Human(Mover, Attacker):
def __init__(self, world, speed, range):
Mover.__init__(self, world, speed)
Attacker.__init__(self, world, range)
Run Code Online (Sandbox Code Playgroud)
我也只能调用Mover
构造函数,例如,简单地初始化Human
的_range
明确,但在我这个跳出一个多糟糕的方法,因为它复制了初始化代码的Attacker
.
就像我说的那样,我知道将_world
属性设置两次并不是什么大不了的事,但是你可以想象如果有更密集的东西继续存在Actor.__init__
,这种情况会让人担心.任何人都可以建议在Python中实现这个结构的更好的做法吗?
你在这里得到的是钻石继承.Python对象模型通过方法解析顺序算法解决了这个问题,该算法使用C3线性化 ; 实际上,你所要做的就是使用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)
Run Code Online (Sandbox Code Playgroud)
请注意,您现在需要Human
使用kwargs样式构造:
human = Human(world=world, range=range, speed=speed)
Run Code Online (Sandbox Code Playgroud)
这里到底发生了什么?如果您对__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'>)
Run Code Online (Sandbox Code Playgroud)
为了更好地理解,请阅读Python的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()
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
115 次 |
最近记录: |