PKB
PKB

Reputation: 390

Dictionary comprehension creating unexpected result

I'm learning Python, currently dictionary comprehension. I am playing around with different ideas just to see what I get and I'm getting one I really don't understand. Any help understanding what I'm doing wrong would be really appreciated.

Specifically, this code:

test_dict = {key: val
        for key in ['a','b','c']
        for val in range(3)}
print(test_dict)

Produces the following dictionary: {'a': 2, 'b': 2, 'c': 2}

I'm expecting: {'a': 0, 'b': 1, 'c': 2}

When I run this quick loop:

for val in range(3):
   print(val)

I get:

0
1
2

Is there a reason every dictionary key is getting the same value, the final value of the range iterator?

I'm running Python 3.6.5 via Anaconda / Jupyter notebooks.

Upvotes: 0

Views: 55

Answers (2)

kindall
kindall

Reputation: 184131

Let's blow up your dict comprehension; it's equivalent to the following:

test_dict = {}
for key in ['a','b','c']:
    for val in range(3):
        test_dict[key] = val

So, for each key, you perform three different assignments into your dictionary. Naturally, only the last one is retained.

To get the result you want, just assign ho each key once. An obvious way in this case is to use enumerate() to number the items in the sequence, then use that for the value.

test_dict = {key: val for val, key in enumerate(['a','b','c'])}

For the general case of any two sequences, use zip():

test_dict = {key: val for key, val in zip(['a', 'b', 'c'], range(3))}

Actually, since the dict constructor is happy to consume a sequence of key/value pairs, you can write that this way:

test_dict = dict(zip(['a', 'b', 'c'], range(3)))

Upvotes: 4

Julien
Julien

Reputation: 15071

Your code is equivalent to a 2 nested for loops, for each key you effectively run successively the command test_dict[key] = val for all val, only the last one will remain.

You probably want this instead:

test_dict = {key: val for key,val in zip('abc', range(3))}

or directly

test_dict = dict(zip('abc', range(3)))

Upvotes: 2

Related Questions