Я хочу наложить на героя эффект Берсерка. Абстрактные классы: 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}
в чем моя ошибка?
Вы подверглись жестокому нападению со стороны передача по ссылке.
В вашем коде у вас есть self.stats = self.base.stats
. Это не делает копию. Поэтому self.stats
вместо brs1
и brs2
относятся к такой жеdict
. Когда вы создаете экземпляр brs2
, вы изменяете его, и это изменение отражается в brs1
.
self.stats = self.base.stats.copy()
было бы хорошим началом, если вы не хотите, чтобы это произошло.
Тем не менее, я нахожу довольно странным, что вы хотите закодировать эффекты статуса таким образом... если бы это был я, я бы включил каждый эффект статуса, содержащий только модификатор, и класс персонажа должен был бы справиться с разрешением этих эффектов. модификаторы по очереди.
@hyper Показать что?
... на моем месте каждый статусный эффект содержал бы только модификатор, и класс персонажа должен был бы обрабатывать эти модификаторы по очереди...
из-за следующего кода
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())
Трудно понять, чего вы действительно хотите, но эффект таков, что обе оболочки
Berserk
просто ссылаются на атрибутstats
оригиналаHero
. КаждыйBerserk
увеличивает одну и ту же запись"HP"
, поэтому вы должны обнаружить, что все три экземпляра имеют:stats["HP"] == 142
.