4

I've come across some surprising behavior with Python generators:

>>> def f(n):
...     if n < 2:
...         return [n]
...     for i in range(n):
...         yield i * 2
... 
>>> list(f(0))
[]
>>> list(f(1))
[]
>>> list(f(2))
[0, 2]

Why is no value returned from the generator in the first two cases?

planetp
  • 14,248
  • 20
  • 86
  • 160
  • Possible duplicate of [Return in generator together with yield in Python 3.3](https://stackoverflow.com/questions/16780002/return-in-generator-together-with-yield-in-python-3-3) – vishes_shell Dec 15 '17 at 11:23

2 Answers2

6

Because generator return statements don't return anything, they end the execution (python knows this is a generator because it contains at least one yield statement). Instead of return [n] do

 yield n
 return

EDIT

after raising this with the python core devs, they pointed me to the python docs where it says

In a generator function, the return statement indicates that the generator is done and will cause StopIteration to be raised. The returned value (if any) is used as an argument to construct StopIteration and becomes the StopIteration.value attribute.

So you can do

def f(n):
    if n < 2:
         return [n]
    for i in range(n):
         yield i * 2

g = f(1)
res = []
while True:
    try:
         res.append(next(g))
    except StopIteration as e:
         if e.value is not None:
              res = e.value
         break

if you really, really wanted.

FHTMitchell
  • 11,793
  • 2
  • 35
  • 47
  • 1
    It would be good to add a link to documentation that says the value of `return` is ignored in generators. – alexis Dec 15 '17 at 11:23
  • 3
    In fairness I think this is undocumented behaviour. Why having `return n` in a generator is not a `SyntaxError` is beyond me. This [PEP](https://www.python.org/dev/peps/pep-0255/#specification-return) doesn't describe anything about `return n`. Edit: actually, it's right at the [bottom](https://www.python.org/dev/peps/pep-0255/#then-why-not-allow-an-expression-on-return-too). Still all it says is that it's not allowed, not that it fails silently. – FHTMitchell Dec 15 '17 at 11:25
2

return does not generate iterator. use yield and then return

def f(n):
        if n < 2:
            yield n
            return
        for i in range(n):
            yield i * 2
mehrdadep
  • 972
  • 1
  • 15
  • 37