Класс дополнений в Python - PullRequest
0 голосов
/ 08 июня 2018

Я хотел бы написать класс, который в основном является дополнением к существующим классам.Оно должно быть разработано так, чтобы оно было только наследственным, а не работало само по себе.Пока что я использую что-то вроде этого примера.

class Swordsman: # First self sufficient class
    def __init__(self):
        pass

    def walk(self):
        pass

    def cover(self):
        print('Covering behind my shield')

class Wizard: # Second self sufficient class
    def __init__(self):
        pass

    def walk(self):
        pass

    def cover(self):
        print('Covering behind my robe')

class HealerAddon: # addon class
    def __init__(self):
        pass

    def heal(self):
        self.cover() # this is ugly
        print('healing')

class Paladin(Swordsman,HealerAddon):
    def __init__(self):
        Swordsman.__init__(self)
        HealerAddon.__init__(self)

class Druid(Wizard,HealerAddon):
    def __init__(self):
        Wizard.__init__(self)
        HealerAddon.__init__(self)

if __name__ == '__main__':
    arthos = Paladin()
    arthos.heal()

    druid1 = Druid()
    druid1.walk()
    druid1.heal()

В этом примере Swordsman и Wizard - два самодостаточных класса.HealerAddon - это класс Addon, который можно использовать для добавления возможности лечения к любому из первых двух.Результатом являются два класса Паладин и Друид, которые являются целительными мечниками и волшебниками соответственно.

Пока это работает, но я не очень доволен этим способом, особенно из-за первой строки в исцелении.метод, в котором предполагается существование метода укрытия, хотя это становится понятным только в комбинированных классах друид и паладин, откуда укрытие.

Есть ли лучший способ сделать это?

1 Ответ

0 голосов
/ 08 июня 2018

Как сказано в комментариях: то, что вы хотите, называется классом "mixin".

Обычное соглашение об именах для такого класса заключается в том, что он заканчивается на "mixin", например:

class HealerMixin:
    def __init__(self, *args, **kwargs):
        if type(self) is HealerMixin:
            raise TypeError("HealerMixin cannot be instantiated")
        super().__init__(*args, **kwargs)
    def heal(self, target=None):
        if target is None:
            # heal self
            target = self.name
        self.cover() # this is ugly
        print('healing {!s}'.format(target))

class NameMixin:
    def __init__(self, name, *args, **kwargs):
        if type(self) is NameMixin:
            raise TypeError("NameMixin cannot be instantiated")
        self.name = str(name)
        super().__init__(*args, **kwargs)
    def __str__(self):
        return self.name

Если вы включаете метод __init__ в свой миксин, обычно хорошей идеей является включение сигнатуры (*args, **kwargs) в метод __init__, поскольку это позволяет микшину работать с любым дочерним классом с любымsignature.

class Wizard(NameMixin):
    def cover(self):
        print('{!s} Covering behind my robe'.format(self.name))

class Druid(HealerMixin, Wizard):
    pass

class FlashyDruid(Druid):
    def __init__(self, name):
        super().__init__("~~***{!s}***~~".format(name))
    def cover(self):
        """Overrides Wizard.cover()"""
        print('{!s} Covering behind my glittering robe'.format(self.name))

Возможно, используйте это так:

>>> Gob = FlashyDruid("Gob")
>>> Gob.cover()
~~***Gob***~~ Covering behind my glittering robe
>>> Buster = Druid("Buster")
>>> Buster.heal(Gob)
Buster Covering behind my robe
healing ~~***Gob***~~

Использование super в вашем методе __init__ делает так, что наследование классов происходит автоматически.Вам не нужно самостоятельно продумывать наследование самостоятельно.

Обратите внимание, что иногда становится важным наследовать класс mixin в правильном порядке : сначала идут mixins, а потом базовые классы (еслиесть такие)Если вы этого не сделаете, вы будете вызывать ошибки.Например, в некоторых случаях миксин будет пытаться посылать аргументы классам, которые не знают, что с ними делать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...