Welcome, guest | Sign In | My Account | Store | Cart

This is a rewrite of my previous recipe http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/389202. Instead of returning the series as a list, this one creates another generator instead.

Python, 34 lines
 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
30
31
32
33
34
# Simple series generator with
# multiple generators & decorators.
# Author : Anand B Pillai

def myfunc(**kwds):

    def func(f):
        cond = kwds['condition']
        proc = kwds['process']
        num = kwds['number']

        x = 0
        for item in f():
            
            if cond and cond(item):
                if proc: item = proc(item)
                yield item
                x += 1
                
            if x==num:
                break

    return func

def series(condition=None, process=None, number=10):

    @myfunc(condition=condition,process=process,number=number)    
    def wrapper():
        x = 1
        while 1:
            yield x
            x += 1

    return wrapper

The only difference between this and the original recipe is that the series function ultimately returns a generator for the series here, not the final list.

So it should be used like...

for item in series(condition=lambda x: x, process=lambda x: x*x, number=100): do_whatever_with(item)

This could be more useful than the original recipe, since the result is a custom generator for the kind of series you want, with the required size.

6 comments

Daniel Arbuckle 19 years, 1 month ago  # | flag

Better way. There is a easier to read, standard solution to this problem using the itertools module:

from itertools import count, islice, imap, ifilter

imap(proc, ifilter(cond, islice(count(), num)))
Anand (author) 19 years, 1 month ago  # | flag

Does this return a generator? I have not used itertools. This returns a generator, does

your solution also return a generator?

This recipe was written to show how to combine a generator with

a function decorator to make another generator.

Daniel Arbuckle 19 years, 1 month ago  # | flag

Yep, its a generator. Yes, the itertools version returns a generator.

As for wrapping generators with decorators, since your goal is to show how it works, maybe you should provide an example without unnecessary frosting. Maybe something like:

def squared(f):
    def wrapper(*args, **kw):
        for i in f(*args, **kw):
            yield i ** 2
    return wrapper

@squared
def series(n):
    i = 0
    while i != n:
        yield i
        i += 1
Daniel Arbuckle 19 years, 1 month ago  # | flag

Another way, for simple sequences. If you're using Python 2.4 or later, generator expressions make an even more readable solution:

(proc(x) for x in xrange(num) if cond(x))
Anand (author) 19 years, 1 month ago  # | flag

Not the same problem... The recipe was written to show how to extract a custom series

out of any infinite generator. Though the code shows the simplest

generator, i.e the one which returns a sequence of positive numbers it can be extended to any complex generator . The generator expression can do it only for the simplest generator.

Again, your solutions are (probably) more readable and faster(I

timed the itertools one with my code and it performs at least 3 times faster), but the purpose of the recipe is not to add a lot of code in your original generator, but to make it do something else by decorating.

Daniel Arbuckle 19 years, 1 month ago  # | flag

OK, but... I only added the generator expression for the sake of people who are looking to solve the problem your recipe explicitly addresses, rather than the one you meant to address. My apologies for not making that clear.

You are incorrect in the limitations you place on the use of the generator expression. While I used xrange, any generator could have been put there. Further, the expression as written can technically produce any series in which the values are a function of the index, which is to say any series at all. You just need the right proc() function or expression.

Created by Anand on Wed, 23 Feb 2005 (PSF)
Python recipes (4591)
Anand's recipes (38)

Required Modules

  • (none specified)

Other Information and Tasks