Задать вопрос
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)
  • Вопрос задан
  • 132 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 2
Maksim_64
@Maksim_64
Data Analyst
далее создал 2 бойца (боец 1 и боец 2) и присвоил им класс fighter

Ты создал два экземпляра класса fighter (в python принято давать имена классам с заглавной буквы) fighter-> Fighter.

далее я бойцом 1 применил метод удар на бойца 2
Это тебе так захотелось, в описании метода класса 'udar' об этом нет слова. Твой класс умеет бить только собственный экземпляр точнее имеет намерение ударить себя (так как атрибут здоровья не обновляется)

Нужно передавать экземпляр другого класса, в общем измененная версия твоего кода
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

    def udar(self,other):
        print(self.name + " наносит урон с руки" 'c уроном ' + str(self.dmg))
        other.hp = other.hp - self.dmg
        return "У " + other.name + " осталось здоровья: " + str(other.hp)
boec = fighter("вася",200,22)
boec2 = fighter("bob",100,19)
boec.udar(boec2)
Ответ написан
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')
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы