18

I have a newbie question for python gurus.

I have function A that hold a lot of repeated yield-actions like so:

yield a
yield b
yield c

so it looks like:

def funA():
    …
   yield a
   yield b
   yield c
    …
   yield a
   yield b
   yield c
    …
   yield a
   yield b
   yield c

Is there any way to put all repeated yields in function and do something like that?:

def funA():
    …
   yield funB()
    …
   yield funB()
    …
   yield funB()

Update

yield a
yield b
yield c

It's just an example but in a real application its more complex sequence of yields that repeat more then once in main generator (so it's not question about organizing yields) but about sub-generators. So I'd like to avoid code duplication.

Eugene Krevenets
  • 1,791
  • 2
  • 20
  • 35

2 Answers2

28

If you're using the latest and greatest python (>= 3.3), there's the yield from construct.

yield from funB()

It does exactly what you want: you can invoke a function as a sub-generator, and yield back everything it yields to you.

If you're using an earlier version of python, then I'm afraid you'll have to do it manually:

for x in funB(): yield x

If you have a dynamic set of sub-generators, you can do this:

funs = [funA, funB, funC]

for fun in funs:
    for item in fun():
        yield item
salezica
  • 74,081
  • 25
  • 105
  • 166
  • Yes! Thanks! It is exactly what I need, sadly I use 2.7 version. – Eugene Krevenets Nov 22 '13 at 22:02
  • So Is it possible to make such a conclusion: if we have python < 3.3. It's better not to do any sub-generators and just repeat yields? So left function as it was before – Eugene Krevenets Nov 22 '13 at 22:35
  • On the contrary, I think your idea was good. An endless stream of `yield` statements is hard on the eyes. See my edit above for a possible grouping technique – salezica Nov 22 '13 at 22:41
3

itertools.chain is the function you're looking for

import itertools

def funA():
    for x in range(10):
        yield x

def funB():
    for x in range(10,20):
        yield x

def funC():
    for x in range(20,30):
        yield x

def funs():
    for x in itertools.chain(funA(), funB(), funC()):
        yield x

print [x for x in funs()]

Outputs:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
Rebs
  • 4,169
  • 2
  • 30
  • 34