First, consider the following code (I'm going to discuss several versions of subgen() next):
>>> def maingen(i):
... print("maingen started")
... yield from subgen(i)
... print("maingen finished")
...
>>> for i in maingen(5):
... print(i)
...
I want to write several subgen generator functions.
A normal one is:
>>> def subgen_1(i):
... yield i + 1
... yield i + 2
... yield i + 3
No prob, output is as expected:
maingen started
6
7
8
maingen finished
Now, I want an other version of subgen which yields nothing...
If I try that:
>>> def subgen_2(i):
... i * 3
I've an exception:
maingen started
Traceback (most recent call last):
...
TypeError: 'NoneType' object is not iterable
It's expected: subgen_2 isn't a generator function.
OK, next. I can read somewhere (like the first answer here)
that I've to raise a StopIteration. (Note that, as a newbie, I can't comment this answer.)
>>> def subgen_3(i):
... i * 3
... raise StopIteration()
...
As identified in PEP 479, "Finally, the proposal also clears up the confusion about how to terminate a generator: the proper way is return, not raise StopIteration.", I only get:
maingen started
(no maingen finished...)
And the only way I've found to get things OK is:
>>> def subgen_4(i):
... i * 3
... return
... yield
...
With this, I get:
maingen started
maingen finished
Hourrah! But this solution isn't beautiful...
Does anyone have a better or a more pythonic idea?
Is it possible to write a decorator to secretly add the ugly yield statement?
return iter([])if you want the function to run and then result in an empty iterator.subgen_2does not actuallyyieldanything why do you useyield from subgen_2()in the first place?StopIterationto stop the generator (without yielding anything first). It does not change the fact though, that you need to have ayieldstatement in the function body (syntactically), to make it a generator function.yield from [], in any case you are asking how to make an empty generator which is exactly the same as yield break in Python.