Search code examples
pythonpython-2.7tornadocoroutine

Why does adding parenthesis around a yield call in a generator allow it to compile/run?


I have a method:

@gen.coroutine
def my_func(x):
    return 2 * x

basically, a tornado coroutine.

I am making a list such as:

my_funcs = []
for x in range(0, 10):
    f = yield my_func(x)
    my_funcs.append(x)

In trying to make this a list comprehension such as:

my_funcs = [yield my_func(i) for i in range(0,10)]

I realized this was invalid syntax. It turns out you can do this using () around the yield:

my_funcs = [(yield my_func(i)) for i in range(0,10)]
  • Does this behavior (the syntax for wrapping a yield foo() call in () such as (yield foo() ) in order to allow this above code to execute) have a specific type of name?
  • Is it some form of operator precedence with yield?
  • Is this behavior with yield documented somewhere?

Python 2.7.11 on OSX. This code does need to work in both Python2/3 which is why the above list comprehension is not a good idea (see here for why, the above list comp works in Python 2.7 but is broken in Python 3).


Solution

  • yield expressions must be parenthesized in any context except as an entire statement or as the right-hand side of an assignment:

    # If your code doesn't look like this, you need parentheses:
    yield x
    y = yield x
    

    This is stated in the PEP that introduced yield expressions (as opposed to yield statements), and it's implied by the contexts in which yield_expr appears in the grammar, although no one is expecting you to read the grammar:

    A yield-expression must always be parenthesized except when it occurs at the top-level expression on the right-hand side of an assignment.