Python 中具有不同签名的钻石继承
Diamond inheritance in Python with different signatures
设置如下:
class Player(object):
def __init__(self, heigth):
self.heigth = heigth
print('do not forget that this should happen once!')
class Attacker(Player):
def __init__(self, heigth, goal_probability):
super().__init__(heigth)
self.goal_prob = goal_probability
def hit(self):
pass
# implementation
class Goalie(Player):
def __init__(self, heigth, save_probability=0.1):
super().__init__(heigth)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
up = UniversalPlayer(heigth=1.96, goal_probability=0.6)
一切都按预期工作:MRO 首先选择 Attacker
,然后选择 Goalie
。我用 Attacker
的 __init__
签名调用 UniversalPlayer
的构造函数,用 Player
的签名调用 Goalie
的构造函数,它没问题,因为 save_probability
有一个默认值,但 问题是我无法选择 save_probability
, 除了在实例化 up
之后设置 up.save_probability
,我觉得很不雅。
此外,Goalie
没有 save_probability
的默认值,此代码将引发异常。
有没有办法写UniversalPlayer
,这样我也可以选择save_probability
,或者这里有一些根本性的问题无法解决?
__init__
的每个附加参数都需要有一个 class 负责将其从对 super
的调用中移除,这样当 object.__init__
最终被调用时,您不需要' 不小心将任何参数传递给它。此外,每个方法都必须接受任意参数并将它们传递给下一个可能处理的方法。
# Player will be responsible for height
class Player(object):
def __init__(self, height, **kwargs):
super().__init__(**kwargs) # Player needs to use super too!
self.height = height
print('do not forget that this should happen once!')
# Attacker will be responsible for goal_probability
class Attacker(Player):
def __init__(self, height, goal_probability, **kwargs):
super().__init__(height, **kwargs)
self.goal_prob = goal_probability
def hit(self):
pass
# Goalie will be responsible for save_probability
class Goalie(Player):
def __init__(self, height, save_probability=0.1, **kwargs):
super().__init__(height, **kwargs)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
# Pass all arguments
# Life is easier if you stick to keyword arguments when using super().__init__
up = UniversalPlayer(height=1.96, goal_probability=0.6, save_probability=0.2)
现在,Attacker.__init__
是第一个被调用的。它使用 goal_probability
,然后不会将其传递给其他调用。它通过 **kwargs
接受 save_probability
并将其传递给 Goalie.__init__
以最终接收。请注意,Attacker.__init__
和 Goalie.__init__
都不必在其参数列表中显式包含 height
;它也可以通过 **kwargs
接受,最终由 Player.__init__
.
接收
此外,我不确定单独 类 是否是处理这些问题的最佳方式,问题是您的构造函数无法处理未知参数。允许他们使用 *args, **kwargs
表示法。
实际上,所有参数都将传递给每个 __init__
,而未使用的参数将被忽略。
class Player(object):
def __init__(self, *args, **kwargs):
self.height = kwargs['height']
class Attacker(Player):
def __init__(self, goal_probability, *args, **kwargs):
super().__init__(*args, **kwargs)
self.goal_prob = goal_probability
def hit(self):
pass
# implementation
class Goalie(Player):
def __init__(self, save_probability, *args, **kwargs):
super().__init__(*args, **kwargs)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
up = UniversalPlayer(height=1.96, goal_probability=0.6, save_probability=0.2)
设置如下:
class Player(object):
def __init__(self, heigth):
self.heigth = heigth
print('do not forget that this should happen once!')
class Attacker(Player):
def __init__(self, heigth, goal_probability):
super().__init__(heigth)
self.goal_prob = goal_probability
def hit(self):
pass
# implementation
class Goalie(Player):
def __init__(self, heigth, save_probability=0.1):
super().__init__(heigth)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
up = UniversalPlayer(heigth=1.96, goal_probability=0.6)
一切都按预期工作:MRO 首先选择 Attacker
,然后选择 Goalie
。我用 Attacker
的 __init__
签名调用 UniversalPlayer
的构造函数,用 Player
的签名调用 Goalie
的构造函数,它没问题,因为 save_probability
有一个默认值,但 问题是我无法选择 save_probability
, 除了在实例化 up
之后设置 up.save_probability
,我觉得很不雅。
此外,Goalie
没有 save_probability
的默认值,此代码将引发异常。
有没有办法写UniversalPlayer
,这样我也可以选择save_probability
,或者这里有一些根本性的问题无法解决?
__init__
的每个附加参数都需要有一个 class 负责将其从对 super
的调用中移除,这样当 object.__init__
最终被调用时,您不需要' 不小心将任何参数传递给它。此外,每个方法都必须接受任意参数并将它们传递给下一个可能处理的方法。
# Player will be responsible for height
class Player(object):
def __init__(self, height, **kwargs):
super().__init__(**kwargs) # Player needs to use super too!
self.height = height
print('do not forget that this should happen once!')
# Attacker will be responsible for goal_probability
class Attacker(Player):
def __init__(self, height, goal_probability, **kwargs):
super().__init__(height, **kwargs)
self.goal_prob = goal_probability
def hit(self):
pass
# Goalie will be responsible for save_probability
class Goalie(Player):
def __init__(self, height, save_probability=0.1, **kwargs):
super().__init__(height, **kwargs)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
# Pass all arguments
# Life is easier if you stick to keyword arguments when using super().__init__
up = UniversalPlayer(height=1.96, goal_probability=0.6, save_probability=0.2)
现在,Attacker.__init__
是第一个被调用的。它使用 goal_probability
,然后不会将其传递给其他调用。它通过 **kwargs
接受 save_probability
并将其传递给 Goalie.__init__
以最终接收。请注意,Attacker.__init__
和 Goalie.__init__
都不必在其参数列表中显式包含 height
;它也可以通过 **kwargs
接受,最终由 Player.__init__
.
此外,我不确定单独 类 是否是处理这些问题的最佳方式,问题是您的构造函数无法处理未知参数。允许他们使用 *args, **kwargs
表示法。
实际上,所有参数都将传递给每个 __init__
,而未使用的参数将被忽略。
class Player(object):
def __init__(self, *args, **kwargs):
self.height = kwargs['height']
class Attacker(Player):
def __init__(self, goal_probability, *args, **kwargs):
super().__init__(*args, **kwargs)
self.goal_prob = goal_probability
def hit(self):
pass
# implementation
class Goalie(Player):
def __init__(self, save_probability, *args, **kwargs):
super().__init__(*args, **kwargs)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
up = UniversalPlayer(height=1.96, goal_probability=0.6, save_probability=0.2)