Search code examples
pythonobjectattributes

add nested attributes to python


the following code

def _say(x): return x

class newObject(object):

    def __init__(self, **kw):
        for x in kw:
            self.x = kw[x]
            for i in self.x:
                a = self.x[i]
                eval('self.x.{u}={t}'.format(u=i, t=a)) #on another note, why would setattr(self.x, i, a) not work
        self.object_ret()

    def object_ret(self):
        return self

data = newObject(**{
        'ranks':{
            'one':['yhggti','aragos','raithinki'],
            'two':['grythin','radios'],
            'three':['riyoken','schrodinger']},
        'nicknames':{
            'riyoken':['theos','arahiron'],
            'illogic':['harab','thing']},
        'commands':{
            'say':_say},
        })

outlines how i want to add further attributes to an object on the end of another attribute. I used to have it like

class newObject(object):

    def __init__(self, **kw):
        [setattr(self, x, kw[x]) for x in kw]
        self.object_ret()

where data.nicknames would return >>> data.nicknames {'illogic': ['harab', 'thing'], 'riyoken': ['theos', 'arahiron']} now I wanted to be able to call data.nicknames.riyoken and return ['theos', 'arahiron'] which would not work with the original setup hence the top portion of the code. The eval('self.x.{u}={t}'.format(u=i, t=a)) part however errors and gives something such as File "<string>", line 1 self.x.say=<function _say at 0x030E9420> ^ SyntaxError: invalid syntax if there is any way possible to get this to work where I could call data.nicknames.riyoken or data.commands.say it would be greatly appreciated.


Solution

  • You mixed up a couple of things. Here is a working version that is close to your code:

    class Attributes:
        pass
    
    class NewObject(object):
        def __init__(self, **kw):
            for x in kw:
                attrs = Attributes()
                setattr(self, x, attrs)
                for i in kw[x]:
                    a = kw[x][i]
                    setattr(attrs, i, a)
    

    And here is how I would do it:

    class NewObject(object):
        def __init__(self, **kwargs):
            for key, value in kwargs.items():
                if isinstance(value, dict):
                    value = NewObject(**value)
                setattr(self, key, value)
    

    This will handle arbitrarily nested dicts.