1

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.

3
  • setattr(self.x, i, a) should work fine. What happened when you tried it? Commented Jun 13, 2016 at 23:12
  • 17, in init setattr(self.x, i, a) AttributeError: 'dict' object has no attribute 'two' Commented Jun 13, 2016 at 23:15
  • I see now. Indeed, you can't set attributes on a dict (and many other built in types). Commented Jun 13, 2016 at 23:20

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

Why not pass data as a parameter to the class when you initialize it? So have the class take a dictionary as an argument. Not sure if I am missing something here.

5 Comments

This should be a comment.
I know... I don't have enough reputation >:(
Well delete this because it's worse now.
Well at least you are kind and friendly and encouraging contribution
I'm sorry, I didn't mean to be mean. I had downvoted because it should have been a comment and I couldn't retract it so I was suggesting you to delete this so that you could get your 2 reputation back. Now that someone has upvoted that no longer applies.
0

Building on @Alex Hall's answer to account for empty dictionaries passed as values:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.