An object's attribute should be random but ends up being the same for all objects of the same class. How come?

So, I’m currently working on the exercise in the Computer Science path where you have to make a game. I decided that it’ll be a fantasy arena simulator with characters that belong to different classes. Each class has it’s own HP die and damage die, so to speak. Here’s how I describe my Barbarian class, for example:

class Barbarian:
    def __init__(self, name, number=1, vocation="Barbarian", hp=random.randint(10, 50), equipment = [], damage_dice=random.randint(4, 8), isDead = False): = name
        self.number = number
        self.vocation = vocation
        self.hp = hp = equipment
        self.damage_dice = damage_dice
        self.isDead = isDead

    def __repr__(self):
        return "{name} — {vocation} [HP: {hp}; Damage: 4-8]".format(name =, vocation = self.vocation, hp = self.hp)

    def attack(self, enemy, bet):
        attack(self, enemy, bet)

    def heal(self):

    def flee(self):

    def die(self):

It’s a work in progress, but what’s bugging me right now is this… I create my characters randomly from a list of names, assigning each of them a class.

def create_characters():
    count = 0
    while count < 10:
        for full_name in full_names:
            char_class = random.randint(1,5)
            for vocation in vocations:
                test_char = vocation(full_names[count])
                if test_char.number == char_class:
                    new_char = vocation(full_names[count])
            count += 1

What I expect to see is that each of them will have their own unique amount of HP. But when I run my code, every character of the same class ends up having the same amount of HP (that’s still generated from the specified range). How come? Shouldn’t every instance of a class with these attributes fire up its own randomizer when it’s created?

Update: I found a workaround by delegating HP generation to an independent function outside of class constructors. But I’m still curious what happened here.

The issue is running random in your init parameters. The default values are only being calculated once then that value is being used subsequently when needed.

Possible alternative;

def __init__(self, name, number=1, vocation="Barbarian", hp=0, equipment = None, damage_dice = 0, isDead = False): = name
  self.number = number
  self.vocation = vocation
  self.hp = random.randint(10,50)
  if is None: = []
  self.damage_dice = random.randint(4,8)
  self.isDead = isDead

For similar reasons your equipment list could also cause you issues later on.

Another alternative is if these properties are always given a default value, even if random, then don’t include them.
Just include those that are going to change.


def __init__(self, name, number=1, vocation="Barbarian"): = name
  self.number = number
  self.vocation = vocation
  self.hp = random.randint(10,50) = []
  self.damage_dice = random.randint(4,8)
  self.isDead = False

Hope that helps