Задать вопрос
dem171
@dem171
3 дня изучаю питон по книге Майкла Доусона

Взаимодействие методов внутри класса?

Доброго времени суток дошел до изучения классов в целом все просто ровно до тех пор пока не появляется необходимость взаимодействие методов внутри класса
Суть такая:
я создал класс fighter и дал ему атрибуты типо name hp и dmg
далее я сделал метод udar в котором по моему мнению я заложил алгоритм нанесения удара
далее создал 2 бойца (боец 1 и боец 2) и присвоил им класс fighter
далее я бойцом 1 применил метод удар на бойца 2 и дальше он как бы должен по формуле из метода удар вычитать из хп бойца 2 урон нанесенный бойцом1 и в конце еше возвращает кол-во хп
ну в общем код у меня не работает

вот так выглядит код программы
class Fighter:
    def __init__(self,name=None,hp=None,dmg=None,):
        self.name = name
        self.hp = hp
        self.dmg = dmg


    def udar(self,hp,dmg):
        print("Наносит урон с руки")
        rep = self.hp - self.dmg
        return "Осталось здоровья: " + rep


boec = Fighter("вася",200,22)
boec2 = Fighter("bob",100,19)
boec.udar(boec2)
  • Вопрос задан
  • 134 просмотра
Подписаться 1 Простой Комментировать
Решение пользователя Vindicar К ответам на вопрос (2)
Vindicar
@Vindicar
RTFM!
# Ты заявляешь следущее:
# "метод udar должен вызываться на экземпляре объекта (self) с двумя параметрами: hp и dmg"
def udar(self,hp,dmg):
    print("Наносит урон с руки")
    # при этом метод не использует переданные параметры?
    rep = self.hp - self.dmg  # почему self.dmg? Боец бьёт себя?
    return "Осталось здоровья: " + rep


# а ниже у тебя:
# метод udar() фактически вызывается с одним параметром: другим бойцом
boec.udar(boec2)


Твоя проблема та же, что и всех новичков: ты не озаботился сформулировать обязанности метода, что должен делать это метод с точки зрения решаемой программой задачи.
Например, сейчас у тебя путаница: метод имитирует нанесение удара бойцом self по бойцу, переданному как параметр? Или же наоборот, удар бойцом, переданным как параметр, по бойцу self? И уж точно не нужно прикручивать сюда ещё и вывод текста в консоль, это посторонняя обязанность, не относящаяся к классу бойца.

Вот моя идея (может, несколько усложнённая, но, надеюсь, понятная):
class Fighter:
    def __init__(self, name: str, hp: int, damage: int):  # указывай типы параметров - так проще понять, что нужно методу
        """Конструктор инициализирует экземпляр бойца заданными значениями."""
        self.name: str = name
        self.hp: int = hp
        self.damage: int = damage
    
    def is_defeated(self) -> bool:
        """Возвращает True, если боец не может более сражаться."""
        return self.hp <= 0  # в простейшем случае, если у бойца не осталось HP

    def calculate_attack_on(self, other: 'Fighter') -> int:
        """Метод определяет, сколько урона наш боец (self) нанесёт бойцу other. Возвращает число очков урона."""
        # сейчас урон всегда одинаков, но потом тут можно будет прикрутить что-то посложнее
        # например, рандомный урон в диапазоне, или бонусы/малусы против конкретных бойцов, или ещё что
        return self.damage  

    def receive_damage(self, damage: int) -> int:
        """Метод определяет, сколько HP наш боец (self) потеряет, получив урон damage, и уменьшает его здоровье. Возвращает число фактически потерянных очков здоровья."""
        # сейчас метод просто вычитает урон из очков здоровья. 
        # но потом при желании можно добавить, например, механику "последний шанс", 
        # когда первый "смертельный" удар оставляет бойца на 1 хп. Или сопротивление/уязвимость к урону, или ещё что.
        lost = min(self.hp, damage)  # если у нас 1 очко здоровья, мы не можем потерять 10
        self.hp -= lost
        return lost

    def attack_other(self, target: 'Fighter') -> int:
        """Проводит атаку нашего бойца (self) по другому бойцу (target). Возвращает нанесённый урон."""
        attack_damage = self.calculate_attack_on(target)
        actual_damage = target.receive_damage(attack_damage)
        return actual_damage

Как видишь, у каждого метода есть свой достаточно чётко очерченный круг обязанностей. Хотя, конечно, можно придраться и сказать, что receive_damage() делает две вещи и его стоит разбить на два метода.
Названия методов должны однозначно указывать, что они делают. Например, udar ничего не говорит о том, кто кого ударяет, тогда как attack_other намекает, что атаку производит тот, у кого вызвали метод, в адрес того, кого передали как параметр метода. То же самое касается параметров методов.
Весь вывод вынесен из класса, это не его обязанность:
boec = Fighter("вася",200,22)
boec2 = Fighter("bob",100,19)
print(f'{boec.name}: {boec.hp} HP;  {boec2.name}: {boec2.hp} HP')
dmg = boec.attach_other(boec2)
print(f'{boec.name} нанёс {dmg} урона {boec2.name}')
print(f'{boec.name}: {boec.hp} HP;  {boec2.name}: {boec2.hp} HP')
Ответ написан