Search code examples
pythongenerator-expression

Why does the following Python generator expression work?


I'm trying to wrap my head around a common generator idiom I encounter in the wild. I've noticed it (and used it) for a long time but never bothered to question it. An example of the idiom using a toy function:

def contains_vowels(string):
    vowels = set('aeiou')

    if any((char in vowels) for char in string):
        return True

    return False

Why does any((char in vowels) for char in string) work as expected? I get that (char in vowels) is a generator expression, but e.g. (char in vowels) for char in string is not a valid generator outside of a function call.

Put another way, given that the above code is valid, why does the following code not work:

    for b in (char in vowels) for char in string:
        print b

(obviously, making the whole expression a generator does work as expected:

    for b in (char in vowels for char in string):
        print b

)

I get that it's a bit of a silly question but the answer isn't immediately intuitive to me. Is it just a case of "because that's the way the syntax works" or is there something I'm missing?


Solution

  • I get that (char in vowels) is a generator expression,

    Actually, it's not. The parentheses are completely superfluous in this case, since there's just a single operator in. When you have more operators, parentheses are used to set order of operations. (1+2)*3 == 9

    (char in vowels) for char in string is not a valid generator outside of a function call.

    Actually it is. Inside a function call you can skip the extra parentheses, when the generator is the only argument. So the following two lines are in effect the same.

    any(char in vowels for char in string)
    any((char in vowels for char in string))
    

    Outside a function call, the generator must have parentheses.

    (char in vowels for char in string)