Python Forum
Run a Function?: Trouble with Online Python Course - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Run a Function?: Trouble with Online Python Course (/thread-37995.html)



Run a Function?: Trouble with Online Python Course - webmanoffesto - Aug-18-2022

Please help me with the below program. My Python is rusty. I'm trying to help my son with the below program. It should return a message like "Pichu (health: 30)", but it only returns nothing. Am I supposed to run a certain function?
What is missing?

class Pokemon():
    def __init__(self):
        self.name = ""
        self.health = 0
    def attack(self, other_pokemon):
        raise NotImplementedError(
            "Sorry, all subclasses have to write their own attack function!")
class Pichu(Pokemon):
    def __init__(self):
        self.name = "Pichu"
        self.health = 30

    def attack(self, other_pokemon):
        other_pokemon.health -= 2
        if other_pokemon.is_alive():
            print("Pichu ZAPPED {}, dealing 2 damage [{}]".format(
                other_pokemon.name, other_pokemon.health))
        else:
            print("Pichu ZAPPED {}, which faints".format(other_pokemon.name))
    def is_alive(self):
        if self.health > 0:
            return True
        else:
            return False

    return "{} (health: {})".format(self.name, self.health)
    def __str__(self):
        pass
    



RE: Run a Function?: Trouble with Online Python Course - Yoriz - Aug-18-2022

This part is not correct
    return "{} (health: {})".format(self.name, self.health)
    def __str__(self):
        pass
the __str__ method should return a string
change it to
    def __str__(self):
        return "{} (health: {})".format(self.name, self.health)
Then create an instance of Pichu and print it
pichu = Pichu()
print(pichu)
Output:
Pichu (health: 30)



RE: Run a Function?: Trouble with Online Python Course - webmanoffesto - Aug-18-2022

thank you! I'll try that


RE: Run a Function?: Trouble with Online Python Course - deanhystad - Aug-18-2022

I would use the abstract base class (abc) module. Declare "attack()" an abstract method and abc will raise an exception when you try to create an instance of an incomplete subclass instead of waiting to call the missing method. Plus you get a better error message.
import abc

class Pokemon(abc.ABC):
    def __init__(self, name="", health=0):
        # Using default arguments instead of hiding default values. Or don't use default arguments and
        # force the user into providing values for name and health.
        self.name = name
        self.health = health

    @abc.abstractmethod
    def attack(self, other_pokemon):
        """Attack another pokemon"""

    def is_alive(self):
        return self.health > 0

    def __str__(self):
        return f"{self.name} (health: {self.health})"


class Pichu(Pokemon):
    def __init__(self):
        # Call superclass __init__().  Push up as much as you can to the superclass.
        super().__init__("Pichu", 30) 

    def attack(self, other_pokemon):
        other_pokemon.health -= 2
        if other_pokemon.is_alive():
            print(
                "Pichu ZAPPED {}, dealing 2 damage [{}]".format(
                    other_pokemon.name, other_pokemon.health
                )
            )
        else:
            print("Pichu ZAPPED {}, which faints".format(other_pokemon.name))


class BadMonster(Pokemon):
    """I am not a proper subclass of Pokemon because I don't have an attack method"""
    def __init__(self):
        super().__init__("Bad Monster", -1)


p = Pichu()
b = BadMonster()
Error:
Traceback (most recent call last): File "...", line 42, in <module> b = BadMonster() TypeError: Can't instantiate abstract class BadMonster with abstract method attack
Other comments:

Push commonality up. is_alive() is likely something all Pokemon support, an likely it will be the same for all Pokemon. Put this in the base class. Same goes for __str__().

Use super(). As is, your code will never call Pokemon.__init__(). You can either drop that method from Pokemon, or you can call it from the subclass __init__() methods.

name and health should be arguments in Pokemon.__init__(). I provided default arguments, but you might want to make these required arguments to the init.