Join the Stack Overflow Community
Stack Overflow is a community of 6.5 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

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 SO question, but wasn't able to intuit how the second for loop works in this case.

share|improve this question

The reason is because of this (fn(i+1), code)) the generator yields a tuple with the first item as either an int or string and the second value as a letter from 'FGHJKMNQUVXZ'

Here is another example of it without the second for loop

def gen_func(text):
    for i, code in enumerate(text):
        yield i, code
        yield str(i), code

print(dict(gen_func('FGHJKMNQUVXZ')))

All the happens with for fn in (int, str) is that fn can then be either the built-in int or str function to convert the value of i.

int(i)
str(i)
share|improve this answer

As you can see fn(i+1) will be called two times. First int(i+1), second str(i+1)

for a in ((fn(i+1), code)
                    for i, code in enumerate('FGH')
                    for fn in (int, str)):
    print a

Output:

(1, 'F')
('1', 'F')
(2, 'G')
('2', 'G')
(3, 'H')
('3', 'H')

for i, code in enumerate('FGH'):
    for fn in (int, str):
        print i, code, fn

Output:

0 F <type 'int'>
0 F <type 'str'>
1 G <type 'int'>
1 G <type 'str'>
2 H <type 'int'>
2 H <type 'str'>
share|improve this answer

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.

share|improve this answer

What the code is making use of is that in python class names can also be used to call the constructor function that returns an instance of that class. For example:

class A(object):
    def __init__(value):
        self.value = value

a = A(10)

Note that A is both a class name, and can also be used as a python callable. The neat thing here is that int and str can also be used in the same way!

z = 10
value = int(z) # returns number 10
print isinstance(value, int) # prints True
print isinstance(value, str) # prints False
value = str(z) # returns '10'
print isinstance(value, int) # prints False
print isinstance(value, str) # prints True

So what the second loop is doing is using str and int as functions that return either the string or integer representation of the index in the first for loop. You can also imagine having written two functions like this:

def as_int(value):
    return int(value)

def as_str(value):
    return str(value)

And then writing the for loop like this:

dict((fn(i+1), code)
for i, code in enumerate('FGHJKMNQUVXZ')
for fn in (as_int, as_str))
 # this second loop loops over the 2-element tuple 
 # whose contents are the two functions `as_int` and `as_str`

As a long-form version of the example.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.