将自变量作为参数传递给混合父方法的正确方法
Correct way of passing a self variable as argument to a mixin parent method
我必须模拟一个战士和他可以执行的不同类型的攻击。这个想法是使用混合来包含攻击逻辑。我的 classes 定义如下:
class Warrior:
def __init__(self, energy):
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self):
self.attacks_cost = {}
def attack(self, attacker, attack_cost):
if attacker.energy < attack_cost:
print('Not enough energy to attack')
else:
attacker.energy -= attack_cost
print('Attack!')
class HandToHandCombatMixin(CombatMixin):
def __init__(self):
super().__init__()
self.attacks_cost['sword_spin'] = 10
def sword_spin(self, attacker):
return self.attack(attacker, self.attacks_cost['sword_spin'])
但是当我尝试测试这个设置时,问题就来了。当我这样做时
class TestTemplarKnight(unittest.TestCase):
def setUp(self):
self.templar = TemplarKnight(energy=100)
def test_templar_knight_can_sword_spin(self):
self.templar.sword_spin(self.warrior)
self.assertEquals(self.templar.energy, 90)
我明白了
def sword_spin(self, attacker):
return self.attack(
> attacker, self.attacks_cost['sword_spin'])
E AttributeError: 'TemplarKnight' object has no attribute 'attacks_cost'
似乎Python认为参数self.attacks_cost
(在HandToHandCombatMixin
sword_spin()
方法中调用self.attack()
时class ) 属于 TemplarKnight
class 而不是 HandToHandCombatMixin
.
我应该如何编写此代码才能使 Python 在 HandToHandCombatMixin
中查找 self.attacks_cost
?
要正确使用super
,所有所涉及的类都需要使用它。现在,首先调用 Warrior.__init__
,但它不使用 super
,因此永远不会调用 HandToHandCombatMixin.__init__
。
进行以下补充:
class Warrior:
def __init__(self, energy, <b>**kwargs</b>):
<b>super().__init__(**kwargs)</b>
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self, <b>**kwargs</b>):
<b>super().__init__(**kwargs)</b>
self.attacks_cost = {}
def attack(self, attacker, attack_cost):
if attacker.energy < attack_cost:
print('Not enough energy to attack')
else:
attacker.energy -= attack_cost
print('Attack!')
class HandToHandCombatMixin(CombatMixin):
def __init__(self, <b>**kwargs</b>):
super().__init__(<b>**kwargs</b>)
self.attacks_cost['sword_spin'] = 10
def sword_spin(self, attacker):
return self.attack(attacker, self.attacks_cost['sword_spin'])
现在,当您实例化 TemplarKnight
时,您将保证以正确的顺序调用所有 __init__
方法。最终,对 super()
的一次调用将导致调用 object.__init__
,此时链最终结束。如果您正确处理了关键字参数,**kwargs
将在发生时为空。
我必须模拟一个战士和他可以执行的不同类型的攻击。这个想法是使用混合来包含攻击逻辑。我的 classes 定义如下:
class Warrior:
def __init__(self, energy):
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self):
self.attacks_cost = {}
def attack(self, attacker, attack_cost):
if attacker.energy < attack_cost:
print('Not enough energy to attack')
else:
attacker.energy -= attack_cost
print('Attack!')
class HandToHandCombatMixin(CombatMixin):
def __init__(self):
super().__init__()
self.attacks_cost['sword_spin'] = 10
def sword_spin(self, attacker):
return self.attack(attacker, self.attacks_cost['sword_spin'])
但是当我尝试测试这个设置时,问题就来了。当我这样做时
class TestTemplarKnight(unittest.TestCase):
def setUp(self):
self.templar = TemplarKnight(energy=100)
def test_templar_knight_can_sword_spin(self):
self.templar.sword_spin(self.warrior)
self.assertEquals(self.templar.energy, 90)
我明白了
def sword_spin(self, attacker):
return self.attack(
> attacker, self.attacks_cost['sword_spin'])
E AttributeError: 'TemplarKnight' object has no attribute 'attacks_cost'
似乎Python认为参数self.attacks_cost
(在HandToHandCombatMixin
sword_spin()
方法中调用self.attack()
时class ) 属于 TemplarKnight
class 而不是 HandToHandCombatMixin
.
我应该如何编写此代码才能使 Python 在 HandToHandCombatMixin
中查找 self.attacks_cost
?
要正确使用super
,所有所涉及的类都需要使用它。现在,首先调用 Warrior.__init__
,但它不使用 super
,因此永远不会调用 HandToHandCombatMixin.__init__
。
进行以下补充:
class Warrior:
def __init__(self, energy, <b>**kwargs</b>):
<b>super().__init__(**kwargs)</b>
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self, <b>**kwargs</b>):
<b>super().__init__(**kwargs)</b>
self.attacks_cost = {}
def attack(self, attacker, attack_cost):
if attacker.energy < attack_cost:
print('Not enough energy to attack')
else:
attacker.energy -= attack_cost
print('Attack!')
class HandToHandCombatMixin(CombatMixin):
def __init__(self, <b>**kwargs</b>):
super().__init__(<b>**kwargs</b>)
self.attacks_cost['sword_spin'] = 10
def sword_spin(self, attacker):
return self.attack(attacker, self.attacks_cost['sword_spin'])
现在,当您实例化 TemplarKnight
时,您将保证以正确的顺序调用所有 __init__
方法。最终,对 super()
的一次调用将导致调用 object.__init__
,此时链最终结束。如果您正确处理了关键字参数,**kwargs
将在发生时为空。