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.
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.
Better way. There is a easier to read, standard solution to this problem using the itertools module:
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.
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:
Another way, for simple sequences. If you're using Python 2.4 or later, generator expressions make an even more readable solution:
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.
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.