python: lambda, yield-statement/expression and loops (Clarify)

Is it any necessity for using yield inside of lambda if you can rewrite it with generator such that?

In[1]: x = (i for i in range(15))
In[2]: x
Out[2]: <generator object <genexpr> at 0x7fbdc69c3f10>

In[3]: print(*x)
Out[3]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

In[4]: x = (i for i in range(0, 15))
In[5]: x.__next__()
Out[5]: 0

In[6]: next(x)
Out[6]: 1

The one-liner you seem to be trying to create is actually technically possible with a lambda, you just need to help the parser a bit more:

>>> lamyield = lambda: [(yield x) for x in range(15)]
>>> print(*lamyield())
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

This uses a for loop implicitly in a list comprehension. It is not possible with an explicit while loop or for loop outside of a comprehension. That's because lambdas in python can only contain expressions, and to write an explicit loop you will need to use statements.

Note: this syntax is deprecated in Python 3.7, and will raise SyntaxError in Python 3.8


You actually can loop through a lambda in useful ways, it's just that the example you provided isn't a great use case.

One instance where you might want to use yield inside a lambda might be to lazily execute expensive functions only when needed. Like so:

def expensive_check1():
    print("expensive_check1")
    return True


def expensive_check2():
    print("expensive_check2")
    return True


def expensive_check3():
    print("expensive_check3")
    return True


def do_the_thing(*args):
    print(args)


if __name__=="__main__":
    for check, args in (lambda: (
                                (yield (expensive_check1(), ["foo", "bar"])), 
                                (yield (expensive_check2(), ["baz"])),
                                (yield (expensive_check3(), [])),
                        ))():
        if check:
            do_the_thing(*args)
            continue
        raise Exception("oh noes!!!")
    else:
        print("all OK!")

Output:

expensive_check1
('foo', 'bar')
expensive_check2
('baz',)
expensive_check3
()
all OK!

Note that the expensive checks only happen at the start of each loop, rather than all at once. Also note that this syntax will still work in Python 3.8+, since it is not using the yield inside of a comprehension.