By TopChef


2010-07-20 22:27:42 8 Comments

I 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 needs only to read the key from the dictionary? Is key a special word in Python? Or is it simply a variable?

10 comments

@chryss 2010-07-20 22:42:58

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 (archived copy).

@Wolf 2016-05-19 12:17:28

As I read these sections about in, the operator part is where you check for existence. Maybe the better delete this in is an operator information.

@Alexander Gessler 2010-07-20 22:29:15

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, in Python 2 use for k,v in s.iteritems(), and in Python 3 for k,v in s.items().

@Andreas Fester 2015-03-26 11:38:35

Note that for Python 3, it is items() instead of iteritems()

@ars 2010-07-20 23:52:08

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().

In Python 3, dict.iterkeys(), dict.itervalues() and dict.iteritems() are no longer supported. Use dict.keys(), dict.values() and dict.items() instead.

@Sadik 2015-06-01 08:49:51

In python3 dict.iterkeys(), dict.itervalues() and dict.iteritems() are no longer supported. Use dict.keys(), dict.values() and dict.items() instead.

@ssoler 2010-07-20 23:49:27

key is simply a variable.

For Python2.X:

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

... or better,

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.iteritems():
    print the_key, 'corresponds to', the_value

For Python3.X:

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.items():
    print(the_key, 'corresponds to', the_value)

@abc 2017-11-03 05:16:06

You can check the implementation of CPython's dicttype on GitHub. This is the signature of method that implements the dict iterator:

_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
             PyObject **pvalue, Py_hash_t *phash)

CPython dictobject.c

@sberry 2010-07-20 22:29:33

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 the following:

For Python 2.x:

for key, value in d.iteritems():

For Python 3.x:

for key, value in d.items():

To test for yourself, change the word key to poop.

For Python 3.x, iteritems() has been replaced with simply items(), which returns a set-like view backed by the dict, like iteritems() but even better. This is also available in 2.7 as viewitems().

The operation items() will work for both 2 and 3, but in 2 it will return a list of the dictionary's (key, value) pairs, which will not reflect changes to the dict that happen after the items() call. If you want the 2.x behavior in 3.x, you can call list(d.items()).

@HarisankarK 2017-07-28 09:43:42

Adding an overlooked reason not to access value like this: d[key] inside the for loop causes the key to be hashed again (to get the value). When the dictionary is large this extra hash will add to the overall time. This is discussed in Raymond Hettinger's tech talk youtube.com/watch?v=anrOzOapJ2E

@yugr 2018-08-25 09:06:13

Might make sense to mention that items will be iterated in unpredictable order and sorted is needed to stabilize it.

@JoeyC 2018-11-08 04:45:49

@HarisankarKrishnaSwamy what is the alternative?

@HarisankarK 2018-11-08 21:40:10

@JoeyC d.iteritems() mentioned @ youtu.be/anrOzOapJ2E?t=1306

@ikbel benabdessamad 2019-05-06 08:52:58

by using the items() method the values in the dictionary will be switched, thus using d[key] would be more accurate.

@Russell Lego 2019-06-11 22:25:35

this actually does not work In [10]: d Out[10]: {'id': [1, 2, 3], 'name': ['russell', 'priya', 'ravi']} In [11]: for key, value in d.iteritems(): ...: print key ...: print value ...: name ['russell', 'priya', 'ravi'] id [1, 2, 3]

@Geza Turi 2019-07-13 15:48:45

@yugr Why do you say that ? The docs says Keys and values are iterated over in insertion order. [docs.python.org/3/library/…

@yugr 2019-07-13 20:49:22

@GezaTuri Only starting from Python 3.6 (and there have been rumors this "feature" may be removed again in future versions).

@John La Rooy 2010-07-21 01:27:03

Iterating over a dict iterates through its keys in no particular order, as you can see here:

Edit: (This is no longer the case in Python3.6, but note that it's not guaranteed behaviour yet)

>>> 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 to get into the habit of using format strings:

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

@Gregory Arenius 2018-07-18 16:30:04

From the Python 3.7 release notes: "The insertion-order preservation nature of dict objects is now an official part of the Python language spec."

@Aaron Hall 2017-06-21 02:51:51

Iterating over dictionaries using 'for' loops

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:
    ...

How does Python recognize that it needs only to read the key from the dictionary? Is key a special word in Python? Or is it simply a variable?

It's not just for loops. The important word here is "iterating".

A dictionary is a mapping of keys to values:

d = {'x': 1, 'y': 2, 'z': 3} 

Any time we iterate over it, we iterate over the keys. The variable name key is only intended to be descriptive - and it is quite apt for the purpose.

This happens in a list comprehension:

>>> [k for k in d]
['x', 'y', 'z']

It happens when we pass the dictionary to list (or any other collection type object):

>>> list(d)
['x', 'y', 'z']

The way Python iterates is, in a context where it needs to, it calls the __iter__ method of the object (in this case the dictionary) which returns an iterator (in this case, a keyiterator object):

>>> d.__iter__()
<dict_keyiterator object at 0x7fb1747bee08>

We shouldn't use these special methods ourselves, instead, use the respective builtin function to call it, iter:

>>> key_iterator = iter(d)
>>> key_iterator
<dict_keyiterator object at 0x7fb172fa9188>

Iterators have a __next__ method - but we call it with the builtin function, next:

>>> next(key_iterator)
'x'
>>> next(key_iterator)
'y'
>>> next(key_iterator)
'z'
>>> next(key_iterator)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

When an iterator is exhausted, it raises StopIteration. This is how Python knows to exit a for loop, or a list comprehension, or a generator expression, or any other iterative context. Once an iterator raises StopIteration it will always raise it - if you want to iterate again, you need a new one.

>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']

Returning to dicts

We've seen dicts iterating in many contexts. What we've seen is that any time we iterate over a dict, we get the keys. Back to the original example:

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:

If we change the variable name, we still get the keys. Let's try it:

>>> for each_key in d:
...     print(each_key, '=>', d[each_key])
... 
x => 1
y => 2
z => 3

If we want to iterate over the values, we need to use the .values method of dicts, or for both together, .items:

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

In the example given, it would be more efficient to iterate over the items like this:

for a_key, corresponding_value in d.items():
    print(a_key, corresponding_value)

But for academic purposes, the question's example is just fine.

@jdhao 2017-05-25 13:42:34

I have a use case where I have to iterate through the dict to get the key, value pair, also the index indicating where I am. This is how I do it:

d = {'x': 1, 'y': 2, 'z': 3} 
for i, (key, value) in enumerate(d.items()):
   print(i, key, value)

Note that the parentheses around the key, value is important, without the parentheses, you get an ValueError "not enough values to unpack".

@Neil Chowdhury o_O 2015-12-31 18:39:18

To iterate over keys, it is slower but better to use my_dict.keys(). If you tried to do something like this:

for key in my_dict:
    my_dict[key+"-1"] = my_dict[key]-1

it would create a runtime error because you are changing the keys while the program is running. If you are absolutely set on reducing time, use the for key in my_dict way, but you have been warned ;).

Related Questions

Sponsored Content

13 Answered Questions

[SOLVED] Add new keys to a dictionary?

19 Answered Questions

[SOLVED] Accessing the index in 'for' loops?

  • 2009-02-06 22:47:54
  • Joan Venge
  • 1844864 View
  • 3185 Score
  • 19 Answer
  • Tags:   python loops list

31 Answered Questions

[SOLVED] "Least Astonishment" and the Mutable Default Argument

18 Answered Questions

[SOLVED] Convert bytes to a string?

40 Answered Questions

[SOLVED] How do I efficiently iterate over each entry in a Java Map?

41 Answered Questions

[SOLVED] How to merge two dictionaries in a single expression?

27 Answered Questions

[SOLVED] What is the best way to iterate over a dictionary?

  • 2008-09-26 18:20:06
  • Jake Stewart
  • 1412237 View
  • 2332 Score
  • 27 Answer
  • Tags:   c# dictionary loops

16 Answered Questions

[SOLVED] Check if a given key already exists in a dictionary

  • 2009-10-21 19:05:09
  • Mohan Gulati
  • 3021401 View
  • 2683 Score
  • 16 Answer
  • Tags:   python dictionary

34 Answered Questions

[SOLVED] How do I sort a dictionary by value?

11 Answered Questions

[SOLVED] Use of *args and **kwargs

  • 2010-08-03 08:28:07
  • MacPython
  • 824070 View
  • 1337 Score
  • 11 Answer
  • Tags:   python args kwargs

Sponsored Content