0

I have a list of dictionaries and I'd like to retrieve their name from a loop like :

for d in list_dicts:
    print d.name

list_dicts = [dic1, dic2]
d.name = dic1

Is it possible and how ? Thank you

John Doe
  • 1,570
  • 3
  • 13
  • 22
  • what you mean about name ? do you mean key or value ex: `{key:value}` or you want the name of dictionary ? also your code has many errors! – Mazdak Sep 21 '14 at 18:58
  • 1
    I think he's talking about the dictionary variable names, `dic1` and `dic2` but those are just references so, no you can't get their "names" – ZekeDroid Sep 21 '14 at 19:02

3 Answers3

2

dic1 or dic2 are variable names. They mean nothing. In fact, you can do:

dic1 = {1:2, 3:4}
dic2 = dic1
list_dicts = [dic1, dic2]

And here the list contains two references to the same dictionary!

If you really need a name, you can either simply add it to the dictionary (kinda hacky, but should work as long as the key is unique):

dic1['name'] = 'dic1'

You could wrap them both in a class:

class NamedDct(object):
    def __init__(self, dct, name):
        self.dct = dct
        self.name = name
dic1 = NamedDct(dic1, 'dic1')

Or you could inherit from dict (please note that this is a degenerate example, not diving into the details):

class NamedDct(dict):
    def __init__(self, name):
        self.name = name
        super(NamedDct, self).__init__()
dic1_new = NamedDct('dic1')
dic1_new.update(dic1)
Korem
  • 11,383
  • 7
  • 55
  • 72
  • I think I'm gonna go for the inheritance. Thank you ! ;) – John Doe Sep 21 '14 at 19:07
  • A note; as implemented in that example, you will lose all of the various was of initializing the `dict` at construction time, if that matters to you. – aruisdante Sep 21 '14 at 19:09
  • @aruisdante True. just wanted to put an example, not to dive into it. – Korem Sep 21 '14 at 19:10
  • Just a question : I thought that I didn't have to explicitly initiate the parent class as it is a built-in one, am I wrong ? – John Doe Sep 21 '14 at 19:12
  • 2
    @JohnDoe see [here](http://stackoverflow.com/questions/3387691/python-how-to-perfectly-override-a-dict) for further details – Korem Sep 21 '14 at 19:14
1

You may want to use a namedtuple for something like this.

Named tuples allow the construction of a lightweight name / data combination (in the form of a Python subclass of a tuple) that is perfect for this use case.

Suppose we want a dict that is attached to a name.

(With verbose=True the entire class is printed out for inspection. In normal use, do not include that...)

>>> from collections import namedtuple
>>> NamedDict = namedtuple('NamedDict', 'name data', verbose=True)
class NamedDict(tuple):
    'NamedDict(name, data)'

    __slots__ = ()

    _fields = ('name', 'data')

    def __new__(_cls, name, data):
        'Create new instance of NamedDict(name, data)'
        return _tuple.__new__(_cls, (name, data))

    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new NamedDict object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != 2:
            raise TypeError('Expected 2 arguments, got %d' % len(result))
        return result

    def __repr__(self):
        'Return a nicely formatted representation string'
        return 'NamedDict(name=%r, data=%r)' % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values'
        return OrderedDict(zip(self._fields, self))

    def _replace(_self, **kwds):
        'Return a new NamedDict object replacing specified fields with new values'
        result = _self._make(map(kwds.pop, ('name', 'data'), _self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result

    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        return tuple(self)

    __dict__ = _property(_asdict)

    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        pass

    name = _property(_itemgetter(0), doc='Alias for field number 0')

    data = _property(_itemgetter(1), doc='Alias for field number 1')

Consider

>>> nd=NamedDict('dict1', {1:'one', 2:'two'})
>>> nd
NamedDict(name='dict1', data={1: 'one', 2: 'two'})
>>> nd.name
'dict1'
>>> nd.data
{1: 'one', 2: 'two'}

So you can then associate a name and dict with each pair in a list:

LoT=[
   ('dict1', {1:'one', 2:'two'}),
   ('dict2', {3:'three', 4:'four'})
   ]

NamedDict = namedtuple('NamedDict', 'name data')

LoND=[NamedDict(*t) for t in LoT]

for d in LoND:
    print(d.name, d.data)

Prints:

dict1 {1: 'one', 2: 'two'}
dict2 {3: 'three', 4: 'four'}
dawg
  • 98,345
  • 23
  • 131
  • 206
0

Supposing you have a list with dictionaries like this:

dic1: {"name": "Name1", ...} dic2: {"name": "Name2", ...}

And a list like this: list_dicts = [dic1, dic2]

The way to access dictionary fields are literal notation (with brackets).

for d in list_dicts:
    print d["name"]
  • That doesn't seem to work for me, following your example pretty much exactly, I'm told `TypeError: string indices must be integers, not str`. It seems python wants to believe d is a list rather than a dictionary. – jg3 Feb 24 '15 at 00:43