kouketsu
kouketsu

Reputation: 23

Random name generator for objects

I'm trying to generate a name for each Goblin object, but either they all have the same name or this error happens

import random

max_enemies = 5


class Entity():
    def __init__(self, name, max_hp, min_hp, attack_dmg):
        self.name = name
        self.max_hp = max_hp
        self.min_hp = min_hp
        attack_dmg = attack_dmg

class Goblin(Entity):
    def __init__(self):
        super().__init__()


Enemies = []


def enemy_spawner():
    for x in range(max_enemies):
        random_name_gen = random.randint(1, 10)
        Enemies.append(Goblin(random_name_gen))

enemy_spawner()

for x in range(len(Enemies)):
    print(Goblin.name)

The error

AttributeError: type object 'Goblin' has no attribute 'name'

I've tried making Goblin it's own class with a name but it didn't work either

Upvotes: 2

Views: 924

Answers (2)

Adam Smith
Adam Smith

Reputation: 54183

Your code doesn't produce the same error you posted, getting instead:

>>> enemy_spawner()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in enemy_spawner
TypeError: __init__() takes 1 positional argument but 2 were given

That's expected though, because while your structure is good it's missing a key bit of boilerplate to make it work -- you need to pass the list of arguments down to the superclass's constructor. Try this instead:

class Goblin(Entity):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

Or indeed simply omit the __init__ method entirely!

class Goblin(Entity):
    pass

Also: to do the printing, you'll have to reference the Goblin instance instead of the Goblin class.

for enemy in Enemies:
    print(enemy.name)

Might I suggest a different way, though? Consider building a constructor inside Entity that produces a Goblin with a random name!

class Entity:

    # As above
    def __init__(self, *args, **kwargs):
        self.name = name
        self.max_hp = max_hp
        self.min_hp = min_hp
        attack_dmg = attack_dmg

    # this is new!
    @classmethod
    def with_random_name(cls, name_generator=some_name_generator_function, *args, **kwargs):
        return cls(name=name_generator(), *args, **kwargs)

# Set some default values if all goblins should be the same
class Goblin(Entity)
    min_hp, max_hp = 5, 10  # or whatever
    attack_damage = 2       # or whatever
    
    def __init__(self, name, min_hp, max_hp, attack_damage, *args, **kwargs):
        super().__init__(*args,
            min_hp=self.min_hp,
            max_hp=self.max_hp,
            attack_damage=self.attack_damage,
            **kwargs)

This will let you do:

for _ in range(num_enemies):
    enemy = Goblin.with_random_name()
    enemies.append(enemy)

Upvotes: 2

U13-Forward
U13-Forward

Reputation: 71570

You could try adding *args to __init__. And also just getting the name attribute from the actual values from the Enemies list:

import random

max_enemies = 5


class Entity():
    def __init__(self, name, max_hp=None, min_hp=None, attack_dmg=None):
        self.name = name
        self.max_hp = max_hp
        self.min_hp = min_hp
        attack_dmg = attack_dmg

class Goblin(Entity):
    def __init__(self, *args):
        super().__init__(*args)


Enemies = []




def enemy_spawner():
    for x in range(max_enemies):
        random_name_gen = random.randint(1, 10)
        Enemies.append(Goblin(random_name_gen))

enemy_spawner()

for x in Enemies:
    print(x.name)

Example output:

10
9
9
6
2

Upvotes: 1

Related Questions