I think your Vampire init needs to look like

def __init__(self, *args, **kwargs): super().__init__(self,*args, **kwargs) #now, override defaults with class specific data = { "strength": random.randint(14,18), "speed": random.randint(14,18), "intelligence": random.randint(14,18), "knowledge": random.randint(14,18) } for key,value in data.items(): setattr(self,key,value)

Your Player class probably isnt doing what you expect -- for instance, you take a named strength argument -- which you ignore. Then, you apply kwargs, such as strength. Then you overwrite it with the default.

Your approach seems very fragile -- do you want to enforce limits by class? In that case, each class should store the min/max limits, then attributes can be checked against those limits. Then you might simply have a roll() method that goes through each attribute, and randints between the limits -- i.e one loop, not fifty bazillion places where you call randint. less chance of errors.