Search code examples
pythongeneratordecorator

How to decorate a generator in python


So, I defined a simple generator:

def gen1(x):
    if x <= 10:
        yield x
        for v in gen1(x + 1):
            yield v

Basically, I want to decorate it so it returns all the values, but the last:

def dec(gen):

    def new_gen(x):
        g = gen(x)
        value = g.next()
        for v in g:
            yield value
            value = v

    return new_gen

Now, if I redefine gen1

@dec
def gen1(x):
    ...

for i in gen1(1):
    print i    # Nothing printed

but if I use:

some_gen = dec(gen1)

for i in some_gen(1):
    print i    # Prints 1 to 9, as needed

Why my decorator doesn't work and how can I fix it?


Solution

  • The recursive invocation of your gen1 is also subject to your decorator, so everything gets consumed by the decorator.

    The simplest fix is to write the generator in non-recursive style, or to encapsulate the recursion:

    Encapsulated:

    @dec
    def gen1(x):
        def inner(x):
            if x <= 10:
                yield x
                for v in inner(x + 1):
                    yield v
        return inner(x)
    

    Non-recursive:

    @dec
    def gen1(x):
        for v in range(x, 11):
            yield v