Mark
Mark

Reputation: 744

How to access index, key and value in Python

I have a generator:

def get_items(self):
        for item in self.info.get_data():
            item = {
                '_name': item.name,
                '_email': item.email,
            }
            yield item

I want to iterate over this generator, assign index to each item key, and then store them in a dict like so:

items = ['item_0_name': 'example name', 'item_0_email': '[email protected]', 
         'item_1_name': 'Some name', 'item_1_email': '[email protected]' ....]

I use enumerate to get index, but then I can't access item's key to add index to it:

items = []
for i, item in enumerate(self.get_items()):
    items['item_'.join(str(i)).join(self.get_items()[i])] = item

But then I'm getting:

TypeError: 'generator' object has no attribute '__getitem__

Is there any Pythonic way to do this?

Upvotes: 1

Views: 470

Answers (2)

msvalkon
msvalkon

Reputation: 12077

Try the following:

items = []
for i, item in enumerate(self.get_items()):
    items.append({'item_{}{}'.format(i, k): v for k, v in item.iteritems()})

List demo:

In [54]: for i, j in enumerate(get_items(test)):
    items.append({'item_{}{}'.format(i, k): v for k, v in j.iteritems()})
   ....:     

In [55]: items
Out[55]: 
[{'item_0_email': '[email protected]', 'item_0_name': 'example_name'},
 {'item_1_email': '[email protected]', 'item_1_name': 'Some name'}]

I assume that what you actually want to do is to append these dictionaries to a list, because, well, items is defined as a list. Otherwise if you want to add these to a dictionary, do the following:

items = {} # Items is now a dictionary
for i, item in enumerate(self.get_items()):
    items.update({'item_{}{}'.format(i, k): v for k, v in item.iteritems()})

Dictionary demo

In [56]: items = {}

In [57]: for i, j in enumerate(get_items(test)):
    items.update({'item_{}{}'.format(i, k): v for k, v in j.iteritems()})
   ....:     

In [58]: items
Out[58]: 
{'item_0_email': '[email protected]',
 'item_0_name': 'example_name',
 'item_1_email': '[email protected]',
 'item_1_name': 'Some name'}

Remember that self.get_items() yields dictionaries. That means you'll have to deal with all of the items in the dictionary. And the above methods are doing exactly that.

The code uses dict comprehensions. They are like list comprehensions but, in this case, iterate over the keys and values of the each dictionary that the self.get_items() generator yields.

Upvotes: 3

Joël
Joël

Reputation: 2822

The error you get is due to the fact that self.get_items() is a generator, and such objects do not permit to do such thing as self.get_items()[1] because in terms of meaning, there is no history.

But in your case, you just missed that self.get_items() yields one dict at each call. You just have to make use of that dict:

items = []
for i, item_dict in enumerate(self.get_items()):
    for key, item in item_dict:
        items['item_{0}{1}'.format(i, key)] = item

By the way, you have another strong error (that I did not correct in my example above): items is a list, so your attempt to do items[some_not_yet_defined_string] = something will fail, first because the index is of str type, and second because you cannot append stuff to list by specifying new indexes.

Moreover, your call to 'item_'.join(str(i)).join [...] is not what you expect: str.join(iterable) returns a string made of the iterable items separated by the given str. It's not generating multiple strings, and will surely not generate several keys for your items dict.

Upvotes: 2

Related Questions