2

I have a list of dicts and I need to access dicts values as attributes.

My code:

class Comments:

    def __init__(self):
        self.comments = [{'id': 1, 'title': 'bla'},
                         {'id': 2, 'title': 'bla2'},
                         {'id': 3, 'title': 'bla3'}]

    def __iter__(self):
        return iter(self.comments)

So, when I write something like:

comment_list = Comments()
for comment in comment_list:
    print comment['id']

It works.

But I want to use attributes as comment.id instead of comment['id'].

How to realize that?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • 6
    Why would you want that? That is not how dicts work. It will confuse people who read your code – Tim Jun 15 '16 at 11:41
  • You would use [setattr()](https://docs.python.org/3/library/functions.html#setattr). – C14L Jun 15 '16 at 11:50

5 Answers5

5

As @Tim Castelijns said, that's not how dicts work.

The behavior you seek can be achieved by having a Comment class which holds the id and title as members.

class Comment

    def __init__(self, id, title):
       self.id = id
       self.title = title

class CommentsHolder:

    def __init__(self):
        self.comments = [Comment(1,'bla'),
                         Comment(2,'bla2'),
                         Comment(3, 'bla3')]

    def __iter__(self):
        return iter(self.comments)

You can then do:

for comment in CommentsHolder():
    print(comment.id)

Furthermore, you can take a look at the Bunch module, which is a dot-accessible dictionary. However if you are using python 3, be aware that it might not work. (at least it didn't for me.)

DJanssens
  • 17,849
  • 7
  • 27
  • 42
0

You can probably use Bunch for this.

Bunch is a dictionary that supports attribute-style access, a la JavaScript

user1337
  • 494
  • 3
  • 13
0

Another approach for completeness - use a namedtuple.

from collections import namedtuple

Comment = namedtuple('Comment', ('id', 'title'))
comments = [Comment(42, 'What is the answer to life, the universe, and everything?'),
            Comment(13, 'What is your favorite color?'),
            Comment(14, 'What is your quest?'),
            Comment(15, 'What is the airspeed velocity of an unladen swallow?'),
            ]

for comment in comments:
    print('{}: {}'.format(comment.id, comment.title))

# or
for comment in comments:
    comment = comment._asdict()
    print('{}: {}'.format(comment['id'], comment['title']))
Wayne Werner
  • 49,299
  • 29
  • 200
  • 290
0

You can make the comments instances of a dictionary subclass that allows normal access as well as dotted attribute-style access. There are several ways of implementing it, but the following is one of the simplest, which is to make the each instance its own __dict__:

class Comment(dict):
    def __init__(self, *args, **kwargs):
        super(Comment, self).__init__(*args, **kwargs)
        self.__dict__ = self

class Comments(object):
    def __init__(self):
        self.comments = [Comment({'id': 1, 'title': 'bla'}),
                         Comment({'id': 2, 'title': 'bla2'}),
                         Comment({'id': 3, 'title': 'bla3'})]

    def __iter__(self):
        return iter(self.comments)

comment_list = Comments()
for comment in comment_list:
    print(comment.id)

Note that Comment dictionaries can be created any of the many ways regular dictionaries can, so in addition to what is shown above, the instances in the comments list could have been created like this which uses keywords to define their contents:

class Comments(object):
    def __init__(self):
        self.comments = [Comment(id=1, title='bla'),
                         Comment(id=2, title='bla2'),
                         Comment(id=3, title='bla3')]
martineau
  • 119,623
  • 25
  • 170
  • 301
0
class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

class Comments:
    def __init__(self):
        self.comments = [{'id': 1, 'title': 'bar'},
                         {'id': 2, 'title': 'foo'},
                         {'id': 3, 'title': 'spam'}]

    def __iter__(self):
        return iter(self.comments)

comment_list = Comments()
for comment in comment_list:
    print(AttrDict(comment).id)

AttrDict used from here.

Community
  • 1
  • 1
Gábor Fekete
  • 1,343
  • 8
  • 16