1

I am attempting to create a child object from random variables within a list. I have included all code that I have tried. Googling the errors brings up many posts and solutions, none of which seem to be exactly parallel enough for me to utilize. Thanks for your time and consideration.

import random


class Monster:

    def __init__(self, name, level):
        self.name = name
        self.level = level


class Dragon(Monster):

    def breathe_fire(self):
        print("The Dragon breathes fire!")


class Skeleton(Monster):

    def strikes(self):
        print("The Skeleton strikes with its sword!")


MONSTERS = ["Skeleton", "Dragon"]
monster_type = random.choice(MONSTERS)
monster_level = 1
monster_stats = [monster_type, monster_level]
print(monster_stats)
# create object from child class and pass stats
#monster = random.choice(MONSTERS(*monster_stats)) <--'list' object is not callable
#monster = Dragon(*monster_stats) # <-- works, but is useless for my purposes
#monster = monster_type(*monster_stats)  <---  'str' object is not callable
misfit138
  • 61
  • 7

2 Answers2

2

You have quotes ("") around Skeleton and Dragon - making them strings

Remove the quotes to reference the class rather than the string

Note: this will not fix the error in this line: monster = random.choice(MONSTERS(*monster_stats))

To fix this, use: monster = random.choice(MONSTERS)(*monster_stats)

The Thonnu
  • 3,578
  • 2
  • 8
  • 30
2

Try this:

import random


class Monster:
    name = None

    def __init__(self, level):
        self.level = level


class Dragon(Monster):
    name = "Dragon"

    def attack(self):
        print("The Dragon breathes fire!")


class Skeleton(Monster):
    name = "Skeleton"

    def attack(self):
        print("The Skeleton strikes with its sword!")


MONSTERS = [Skeleton, Dragon]

monster_cls = random.choice(MONSTERS)
monster_level = 1
monster_stats = [monster_level]  # maybe you have other stats too

monster = monster_cls(*monster_stats)

The main fix is to have a list of classes instead of strings: MONSTERS = [Skeleton, Dragon]

A couple of other suggestions:

  • if the name is the type of the monster (and not an individual name like Smaug) then it doesn't need to be an arg to __init__
  • you might find the rest of the code easier if all the monsters have a common method for making an attack, otherwise when you make a battle you will have to have lots of code like "if monster is a Dragon then breathe_fire else if monster is a Skeleton then strike"
Anentropic
  • 32,188
  • 12
  • 99
  • 147
  • I truly appreciate it. Thank you. I am old and my brain is not as good as it used to be, so this information helps me to learn. I do have a common method or function for attacking, I guess I will have to find some elegant logic to have unique weapons. Perhaps each monster's weapon can be an object? – misfit138 Jun 24 '22 at 17:59
  • If each monster has one type of attack then it's easy enough - the `attack` method on each monster class performs whatever unique logic is needed for that particular monster type's weapon. It gets more complicated if there are monsters with multiple attacks per turn, or they have to choose one of several possible attack actions. You might make the weapon an object if for example there were multiple monsters that all used "long sword" attack - you could then implement the attack logic once in a `class LongSword(Weapon)`. This could easily get very complicated - good luck! – Anentropic Jun 25 '22 at 11:14