странное поведение классов в декораторе шаблонов python - PullRequest
1 голос
/ 29 мая 2019

Я хочу наложить героя на эффект Берсерк. Абстрактные классы: AbstractEffect и AbstractPositive (наследник класса), могут принимать базовый параметр. Далее, AbstractNegative также будет создан. Я не уверен, правильная ли схема наследования (Hero ---> AbstractEffect).

from abc import ABC, abstractmethod 
class Hero:
    def __init__(self):
        self.stats = {"HP": 128}
    def get_stats(self):
        return self.stats.copy()

class AbstractEffect(ABC):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats()

class AbstractPositive(AbstractEffect):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats()

class Berserk(AbstractPositive):
    def __init__(self, base):
        self.base = base
        self.stats= self.base.stats
        self.stats["HP"] += 7
    def get_stats(self):
        return self.stats


hero = Hero() 
brs1 = Berserk(hero) 
print('brs1', brs1.get_stats()) 
brs2 = Berserk(brs1) 
print('brs2', brs2.get_stats()) 
print('brs1', brs1.get_stats())

хочу получить

brs1 {'HP': 135}
brs2 {'HP': 142}
brs1 {'HP': 135}

но я получаю

brs1 {'HP': 135}
brs2 {'HP': 142}
brs1 {'HP': 142}

в чем моя ошибка?

Ответы [ 2 ]

1 голос
/ 29 мая 2019

код следующего кода

self.stats = {"HP": 128}

{"HP": 128} является контейнером
и

self.stats = self.base.stats

Следовательно,
при использовании Berserk(heroxxx) для улучшения героя, self.stats["HP"] += 7 фактически изменяет исходные данные.Поэтому вам нужно изменить его на self.stats = self.base.get_stats(), тогда вы можете получить то, что вы хотите.Вы можете использовать следующий код для проверки.

from abc import ABC, abstractmethod
class Hero:
    def __init__(self):
        self.stats = {"HP": 128}
    def get_stats(self):
        return self.stats.copy()

class AbstractEffect(ABC):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats

class AbstractPositive(AbstractEffect):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats

class Berserk(AbstractPositive):
    def __init__(self, base):
        self.base = base
        self.stats = self.base.get_stats()
        self.stats["HP"] += 7

    def get_stats(self):
        return self.stats.copy()


hero = Hero()
brs1 = Berserk(hero)
print('brs1', brs1.get_stats())
brs2 = Berserk(brs1)
print('brs2', brs2.get_stats())
print('brs1', brs1.get_stats())
0 голосов
/ 29 мая 2019

На вас жестоко напали , передавая по ссылке .

В вашем коде у вас есть self.stats = self.base.stats.Это не делает копию.Следовательно, self.stats для brs1 и brs2 относятся к одинаковым dict.Когда вы создаете экземпляр brs2, вы изменяете его, и это изменение отражается в brs1.

self.stats = self.base.stats.copy() будет хорошим началом, , если вы не хотите, чтобы этослучиться.

Тем не менее, я нахожу довольно странным, что вы хотите закодировать эффекты состояния таким образом ... если бы это был я, я бы имел каждый эффект состояния, содержащий только модификатор, и это было бык классу символов для обработки разрешения этих модификаторов по очереди.

...