Search code examples
pythonclassattributesattributeerrordeclare

Declare class attributes inside a for loop in python


Im trying to create a game which is a rip off of Clash of Clans. The first thing to do is create classes for troops and spells used during the attacking phase. I have defined a class Troop which is a general class, and the idea is all its attributes will be overwritten when declaring specific troops. Here is the barebone Troop class

class Troop():
    def __init__(self):
        self.fav_target = 'any'
        self.damage_type = 'single' #or 'area'
        self.targets = 'ground'
        self.space = 1
        self.speed = 1
        self.dps = 1
        self.hp = 1
        self.type = 'ground' #or 'air'
        self.level = 1
        self.attack_rate = 1

Clash of clans has many troops and each troops attributes (like hp, dps) change with the level. For now i have only implemented those attributes for the highest possible level. To save all the attribute values for specific troops, i have declared dictionaries. Here is the attribute dictionary for a "Barbarian" troop. The format is {'<troop lvl>': {'<attr>': <value>}}

barbs = {'9': {'fav_target': 'any', 'damage_type': 'single', 'targets': 'ground', 'space': 1, 'speed': 16, 
        'dps': 38, 'hp': 230, 'type': 'ground', 'attack_rate': 1}}

Instead of manually overwriting each attribute inside the barbarian class, i thought to use a for loop to overwrite all the attributes inside the barbarian class, like this:

class Barbarian(Troop):
    def __init__(self):
        super(Barbarian, self).__init__()
        self.name = 'Barbarian'
        for attr in barbs['9']:
            self.attr = barbs['9'][attr]

Problem is when I print Barbarian.hp, it return the value inside the Troop class instead of the Barbarian class. If I remove the super() statement, then printing something like Barbarian.hp gives an AttributeError.

Is there a way to overwrite (or declare) attributes inside a class inside a for loop?


Solution

  • Add a **kwargs parameter; use setattr in __init__; pass a dictionary to the instance.

    class Barbarian(Troop):
        def __init__(self,**kwargs):
            super(Barbarian, self).__init__()
            self.name = 'Barbarian'
            for attr,value in kwargs.items():
                setattr(self,attr,value)
    
    b = Barbarian(**barbs['9'])