pythonclassduplicatesinstanceduplication

Python class instances are duplicating attributes


Relatively new to OOP, just messing around trying to make an NPC class for a game that should generate different instances of NPC's based on random values unless specified. Just proof-of-concept really.

However the age, gender and race attributes are duplicating for some reason even though they are generated by functions that should return random values.

I've tested the functions individually and they are doing what they're supposed to and are not complicated.

class NPC:
    def __init__(self, gender = rand_gender(), race = rand_race(),
                 age = rand(16, 70),name = "", height = 0):
        self.gender = gender
        self.race = race
        self.age = age
        if name == "":
           self.name = name_gen(self.gender)
        else: self.name = name
        if height == 0:
            self.height = height_gen(self.race)
        else: self.height = height

def rand(min, max):
    return random.randrange(min, max)

def rand_gender():
    genders = ["Male", "Female"]
    random.shuffle(genders)
    return genders[0]

def rand_race():
    races = ["Human", "Dwarf", "Elf", "Orc"]
    random.shuffle(races)
    return races[0]

npc1 = NPC()
npc2 = NPC()
npc3 = NPC()
hero = NPC("Female","Human", 26, "Hero")

print npc1
print npc2
print npc3
print hero
print npc1 == npc2

This is my class definition and the functions it is using that I'm having trouble with. The name and height functions and the__str__ method seem to be okay so I haven't included them. As you can see the gender, age and race are duplicated. Why is this happening? Can you use functions to initialize class objects?

Output:

Name: Jane Gender: Female Age:32 Race: Elf Height: 6.4
Name: Wilma Gender: Female Age:32 Race: Elf Height: 6.7
Name: Jane Gender: Female Age:32 Race: Elf Height: 6.5
Name: Hero Gender: Female Age:26 Race: Human Height: 5.7
False

Solution

  • This is an extremely common gotcha of python. The function definition (in this case with the named parameters) is only run once! So all the defaults are only being set once.

    class NPC:
        def __init__(self, gender = rand_gender(), race = rand_race(),
                     age = rand(16, 70),name = "", height = 0): # run only once
    

    Try doing something like

    class NPC:
        def __init__(self, gender = None, ...):
             if gender is None:
                gender = rand_gender()
             # init the rest
    

    As suggested, here is even more gotchas