2

This is a result of my answer to another question.

  1. Why do I get a TypeError as described below?
  2. What's the deal with enumerate?

I thought that

for k, v in enumerate(iterable)`

was equivalent to:

for k in iterable:
    v = iterable[k]

Apparently it's not. Or at least, it's not equivalent in all circumstances.

Python docs say:

... seasons = ['Spring', 'Summer', 'Fall', 'Winter']

... list(enumerate(seasons))

[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

... list(enumerate(seasons, start=1))

[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

I would have thought then, that enumerate({1:(1,0)} would return (1, (1,0)).

It doesn't though, it returns an enumerate object:

=> print enumerate(['list'])
<enumerate object at 0x204bb80>

What's really weird is the type of error, and when it's thrown (why do the first two loops go?) when you do things wrong.

Question 1: why does this error occur?

dicModul = {0:(0,1),1:(1,1), 2:(2,3,4,5,6,1,7,2), 
              3:(8,1),4:(9,9), 5:(10,10,5,11,0,12,13), 6:(10,11,9,7)}

for val_outerloop, key_outerloop in enumerate(dicModul):
    for val_innerloop, key_innerloop in enumerate(dicModul):
        print "outerloop {}:{}".format(key_outerloop, val_outerloop)
        print "innerloop {}:{}".format(key_innerloop, val_innerloop)
        for x in val_innerloop:
            print "loops!"

Output of the above code:

outerloop 0:0
innerloop 0:0
Traceback (most recent call last):
  File "python", line 8, in <module>
TypeError: 'int' object is not iterable

I can't figure out what an enumerate object is (doesn't seem to be in the python docs), and in any case, based on those docs, what I'm trying to do shouldn't it doesn't seem throw an error, especially not the TypeError that it's throwing.

Background info is below.

I know (or thought I knew) the following:

Enumerate() allows you to get both the keys and values of items in your dictionary, or the iteration number and value if you are looping through a list.

With regard to your issue with iterating over single items. Tuples are weird, especially with single items. You need the trailing comma or it's not a tuple, it's an int. Honestly, that strikes me as a bug, not a feature, but optimistically, it's probably important for some computer-sciency reason that's way beyond my paygrade. Also, the big thing that distinguishes lists [] and tuples () is that tuples are immutable. You probably don't need to be using tuples in this case:

loopy = (1,)
for x in loopy:
    print x # this will _not_ raise an error

loopy = (1)
for x in loopy:
    print x # this _will_ raise an error

loopy = [1]
for x in loopy:
    print x # this will _not_ raise an error

loopy = 1
for x in loopy:
    print x # this _will_ raise an error

Here are two sets of code:

Codeset 1

dicModul = {0:(0,1),1:(1,1), 2:(2,3,4,5,6,1,7,2), 
          3:(8,1),4:(9,9), 5:(10,10,5,11,0,12,13), 6:(10,11,9,7)}

for val_outerloop, key_outerloop in enumerate(dicModul):
    for val_innerloop, key_innerloop in enumerate(dicModul):
        print "outerloop {}:{}".format(key_outerloop, val_outerloop)
        print "innerloop {}:{}".format(key_innerloop, val_innerloop)

which outputs:

outerloop 0:0
innerloop 0:0
outerloop 0:0
innerloop 1:1
... (you get the idea) ...
innerloop 3:3
outerloop 6:6
innerloop 4:4
outerloop 6:6
innerloop 5:5
outerloop 6:6
innerloop 6:6

Codeset 2

for key_outerloop in dicModul:
    for key_innerloop in dicModul:
        val_outerloop = dicModul[key_outerloop]
        val_innerloop = dicModul[key_innerloop]
        print "outerloop {}:{}".format(key_outerloop, val_outerloop)
        print "innerloop {}:{}".format(key_innerloop, val_innerloop)

which outputs (more what I would expect):

outerloop 0:(0, 1)
innerloop 0:(0, 1)
outerloop 0:(0, 1)
innerloop 1:(1, 1)
outerloop 0:(0, 1)
innerloop 2:(2, 3, 4, 5, 6, 1, 7, 2)
outerloop 0:(0, 1)
innerloop 3:(8, 1)
... (you get the idea) ...
outerloop 6:(10, 11, 9, 7)
innerloop 5:(10, 10, 5, 11, 0, 12, 13)
outerloop 6:(10, 11, 9, 7)
innerloop 6:(10, 11, 9, 7)
Community
  • 1
  • 1
NotAnAmbiTurner
  • 2,553
  • 2
  • 21
  • 44
  • You need to iterate over a dictionary using one of its methods to return what you want: `keys()`, `values()` or a tuple with both (`items()`). This is true whether or not you are using `enumerate()`. – Dan Nov 20 '15 at 01:45
  • `for k in iterable: v = iterable[k]` Nope. `k` is the actual elements in `iterable`, not their indices. – TigerhawkT3 Nov 20 '15 at 01:50
  • Note that enumerate returns index,val and not val,index as shown in the example code above. – stark Apr 03 '16 at 18:24

4 Answers4

3

There are a few misunderstandings here.

enumerate will give you a counting variable, not the key of the dictionary:

l = ['a', 'b', 'c']
for i, entry in enumerate(l):
    print(i, l)

will result in

0 a
1 b
2 c

When you iterate over a dictionary, you are just iterating over the keys:

d = {'a': (2, 3), 'b': (3, 4), 'c': (5, 5)}
for key in d:
    print(key)

will result in

a
b
c

If you want to iterate over both keys and values use d.items() (python3) or d.iteritems() (python2):

d = {'a': (2, 3), 'b': (3, 4), 'c': (5, 5)}
for key, val in d.items():
    print(key, val)

will result in

a (2, 3)
b (3, 4) 
c (5, 5)

You can combine this like this:

for i, (key, val) in enumerate(d.items()):
MaxNoe
  • 14,470
  • 3
  • 41
  • 46
2
for k, v in enumerate(iterable)`

is equivalent to

for k in range(len(iterable)):
    v = iterable[k]

But if iterable is a dict, then your iterable is just the keys. If you want the key-value pairs, you can call dict.items()

maxymoo
  • 35,286
  • 11
  • 92
  • 119
1

An enumerate object is an iterable, that yields values as necessary.

Note:

> print enumerate(['list'])
<enumerate object at 0x204bb80>
> print list(enumerate(['list']))
[(0, 'list')]
1

I think the primary misunderstanding here is that enumerate cares not whether your iterable can be indexed (like a[0] or b['cat']).

The enumerate function just loops and counts. It's the looping, not the indexing that enumerate cares about.

Looping with a dictionary

Looping over a dictionary will loop over the keys:

animals = {'dog': ('betsy', 'miller'), 'cat': ('james', 'mary')}
for item in animals:
    print(item)

This returns:

cat
dog

enumerate

enumerate will enumerate over an iterable and return a new iterable with indices added for each item in the original iterable.

So using enumerate on just a dictionary, we'd expect to see indices and dictionary keys (note that they are unsorted and therefore in an unpredictable order):

animals = {'dog': ('betsy', 'miller'), 'cat': ('james', 'mary')}
for item in enumerate(animals):
    print(item)

This should give us:

(0, 'cat')
(1, 'dog')

items method

The items method will give you key-value pairs for each item in a dictionary.

animals = {'dog': ('betsy', 'miller'), 'cat': ('james', 'mary')}
for key, value in animals.items():
    print("key: {}".format(key))
    print("value: {}".format(value))

This returns:

key: cat
value: ('james', 'mary')
key: dog
value: ('betsy', 'miller')
chepner
  • 497,756
  • 71
  • 530
  • 681
Trey Hunner
  • 10,975
  • 4
  • 55
  • 114