我必须为战士和他可以执行的各种攻击建模。这个想法是使用mixins包含攻击逻辑。我通过以下方式定义了我的课程:
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
(在self.attack()
类的sword_spin()
方法内调用HandToHandCombatMixin
时,属于TemplarKnight
类而不是HandToHandCombatMixin
。
我应该如何编写此代码以使Python在self.attacks_cost
中查找HandToHandCombatMixin
?
要正确使用super
,all相关类需要使用它。现在,首先调用Warrior.__init__
,但它不使用super
,因此从不调用HandToHandCombatMixin.__init__
。
进行以下添加:
class Warrior:
def __init__(self, energy, **kwargs):
super().__init__(**kwargs)
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
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, **kwargs):
super().__init__(**kwargs)
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
在发生时将为空。