Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple 'for' loops in dictionary generator

In this Python documentation the following is used as an example of a generator expression:

dict((fn(i+1), code)
    for i, code in enumerate('FGHJKMNQUVXZ')
    for fn in (int, str))

>> {1: 'F', '1': 'F', 2: 'G', '2': 'G', 3: 'H', '3': 'H', 4: 'J',...}

I don't understand how the second for loop, for fn in (int, str), turns the int value into a string and adds an additional entry to the dictionary.

I have found this Stack Overflow question, but I still wasn't able to intuit how the second for loop works in this case.

like image 899
Sean Avatar asked Dec 27 '16 06:12

Sean


1 Answers

It may help to "unroll" the loops in the generator expression, and write them as independent for loops. To do so, you take all the for (variable) in (iterable) statements and put them on separate lines, in the same order, but move the thing from the front to the body of the innermost for loop. Like this, in general:

thing for a in a_list for b in b_list for c in c_list

becomes

for a in a_list:
    for b in b_list:
        for c in c_list:
            thing

except that when you do the generator expression, all the things automatically go into the list or dictionary or whatever. In your case,

dict((fn(i+1), code)
    for i, code in enumerate('FGHJKMNQUVXZ')
    for fn in (int, str))

becomes

for i, code in enumerate('FGHJKMNQUVXZ'):
    for fn in (int, str):
        (fn(i+1), code)

except that all the tuples will be converted into a dict.

As the other answers explain, you can trace the execution of these two for loops. First, the outer loop sets i to 0 and code to 'F', and within that, the inner loop sets fn to int and then to str, so you get

int(0+1, 'F')
str(0+1, 'F')

after which it goes on to the next i and code.

like image 152
David Z Avatar answered Sep 30 '22 14:09

David Z