Python infinite streamless generator

I am trying to create an endless stream of results with a given function f and an initial value of x, so the first call should give the initial value, the second call should give f (x), the third call should f (x2), and x2 the previous result f (x) and t .d.

what i came up with:

def generate(f, x): return itertools.repeat(lambda x: f(x)) 

which does not seem to work. any ideas? (I can not use the output in my code). also I cannot use more than 1 line of code for this problem. Any help would be appreciated.

also note that in the previous example. I was asked to use profitability. no problem:

 while True: yield x x = f(x) 

this works great. but now .. there is no clue how to do this without

+1
source share
3 answers

In Python 3.3, you can use itertools.accumulate :

 import itertools def generate(f, x): return itertools.accumulate(itertools.repeat(x), lambda v,_:f(v)) for i, val in enumerate(generate(lambda x: 2*x, 3)): print(val) if i == 10: break 
+4
source

I think this works:

 import itertools as it def g(f, x): return it.chain([x],(setattr(g, 'x', f(getattr(g, 'x', x))) or getattr(g, 'x') for _ in it.count())) def f(x): return x + 1 gen = g(f, 1) print next(gen) print next(gen) print next(gen) print next(gen) 

Of course, he relies on some sketchy behavior when I actually add an attribute of the function itself to maintain state. In principle, this function will only work on the first call. After that, all bets are disabled.

If we want to soften this restriction, we can use a temporary namespace. The problem is that to get a temporary namespace, we need a unique instance of the class (or a class, but the instance is cleaner and requires only 1 additional set of brackets). For this to happen on one line, we need to create a new built-in function and use it as the default argument:

 import itertools as it def g(f, x): return (lambda f, x, ns=type('foo', (object,), {})(): \ it.chain([x], (setattr(ns, 'x', f(getattr(ns, 'x', x))) or getattr(ns, 'x') for _ in it.count())) )(f, x) def f(x): return x + 1 gen = g(f, 1) print next(gen) == 1 print next(gen) == 2 print next(gen) == 3 print next(gen) == 4 print "first worked?" gen2 = g(f, 2) print next(gen2) == 2 print next(gen2) == 3 print next(gen2) == 4 

I broke it into several lines, for ease of reading, but it is a 1-liner at heart.

Version without import

(and the most reliable, but I think).

 def g(f, x): return iter(lambda f=f, x=x, ns=type('foo', (object,), {'x':x}): ((getattr(ns, 'x'),setattr(ns, 'x', f(getattr(ns, 'x'))))[0]), object()) 

One trick here is the same as before. We create a lambda function with a mutable default argument to save state. Inside the function, we create a tuple. The first element is what we really want, the second element is the return value of the setattr function, which is used to update the state. To get rid of itertools.chain , we set the initial value in the namespace to x , so the class is already initialized to have the initial state. The second trick is that we use two forms of the iter argument to get rid of it.count() , which was used only to create an infinite iterative earlier. iter continues to call the function that you give it as the first argument until the return value is equal to the second argument. However, since my second argument is an instance of object , nothing returned from our function will ever be equal to it, so we effectively created an infinite itertools without itertools or yield ! Think about it, I believe this latest version is the most reliable. Previous versions had an error in which they relied on the veracity of the return value f . I think they might have failed if f returned 0 . This latest version fixes this error.

+4
source

I assume this is some kind of homework or assignment? So, I would say that you should take a look at generator expressions . Although I agree with other commentators that this seems like an exercise of dubious value ...

0
source

All Articles