views:

224

answers:

6

Am a bit puzzled by the following code:

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:
    print key, 'corresponds to', d[key]

What i don't understand is the 'key' portion. How does python recognize that it only need to read the key from the dictionary? Is key a special word in python? Or is key simply a variable? Further clarification would be much appreciated.

+2  A: 

When you iterate through dictionaries using the for .. in ..-syntax, it always iterates over the keys (the values are accessible using dictionary[key]).

To iterate over key-value pairs, use for k,v in s.iteritems().

Alexander Gessler
+11  A: 

key is just a variable name.

for key in d: will simply loop over the keys in the dictionary, rather than the keys and values. To loop over both key and value you can use for key, value in d.iteritems():

Test for yourself, change the word key to poop

sberry2A
+1 for poop ...
Uku Loskit
Exactly what I was going to write. Kind of unintuitive, one of the few things I really dislike about dicts. I fell into that trap a few times before I got it.
delnan
@delnan: what trap?
John Machin
I, just like the OP, foolishly assumed iterating a dict yielded keys *and* values, not only keys.
delnan
As long as we are discarding foolish assumptions, *also* don't assume that the keys will be in any particular order.
Paul McGuire
@delnan: The Python interactive prompt and `repr()` are your friends. Just **try** stuff instead of assuming ... `for foo in {'a': 1, 'b': 2}: print repr(foo)`
John Machin
+1  A: 

This is a very common looping idiom. in is an operator. For when to use for key in dict and when it must be for key in dict.keys() see David Goodger's Idiomatic Python article.

chryss
A: 

key is simple a variable.

You can do this:

d = {'x': 1, 'y': 2, 'z': 3} 
for poop in d:
    print poop, 'corresponds to', d[poop]

... or better,

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.iteritems():
    print the_key, 'corresponds to', the_value
ssoler
Hey, get your own `poop`!
sberry2A
A: 

It's not that key is a special word, but that dictionaries implement the iterator protocol. You could do this in your class, e.g. see this question for how to build class iterators. In the case of dictionaries, it's implemented at the C level. The details are available in PEP 234. In particular, the section titled "Dictionary Iterators":

Dictionaries implement a tp_iter slot that returns an efficient iterator that iterates over the keys of the dictionary. [...] This means that we can write

      for k in dict: ...

  which is equivalent to, but much faster than

      for k in dict.keys(): ...

  as long as the restriction on modifications to the dictionary
  (either by the loop or by another thread) are not violated.

- Add methods to dictionaries that return different kinds of
  iterators explicitly:

      for key in dict.iterkeys(): ...

      for value in dict.itervalues(): ...

      for key, value in dict.iteritems(): ...

  This means that "for x in dict" is shorthand for "for x in
  dict.iterkeys()".
ars
A: 

as others have pointed out, iterating over a dict iterates through it's keys in no particular order.

As you can see here

>>> d = {'x': 1, 'y': 2, 'z': 3} 
>>> list(d)
['y', 'x', 'z']
>>> d.keys()
['y', 'x', 'z']

For your example it is a better idea to use dict.items()

>>> d.items()
[('y', 2), ('x', 1), ('z', 3)]

This gives you a list of tuples. When you loop over them like this, each tuple is unpacked into k and v automatically

for k,v in d.items():
    print k, 'corresponds to', v

Using k and v as variable names when looping over a dict is quite common if the body of the loop is only a few lines. For more complicated loops it may be a good idea to use more descriptive names

for letter, number in d.items():
    print letter, 'corresponds to', number

It's a good idea going forward to get into the habit of using format strings

for letter, number in d.items():
    print '{0} corresponds to {1}'.format(letter, number)
gnibbler