How to execute a function to every item in a range - python

I got a list of functions after calling the function count() below. I want to know how to execute these functions besides using the way in my code.
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
print(count()[0](), count()[1](), count()[2]())

You can use map to apply a function to every item in an iterable. The result, in Python 3.x, is an iterable.
There are several different ways you can then extract results. Below is an example.
I have also corrected some errors in your logic. Your function f should take a parameter, presumably i, as this is used in your function. Similarly, it seems you want the function count to take a parameter n to determine your range of inputs.
def count(n):
def f(i):
return i*i
return map(f, range(1, n))
## iterate using next
res = count(5)
print(next(res)) # 1
print(next(res)) # 4
print(next(res)) # 9
## iterate using for loop
for k in count(4):
print(k)
# 1
# 4
# 9
## build list and exhaust all results
print(list(count(4)))
# [1, 4, 9]

Related

Iteration for the last value of iteration in Python

How can I define a function in python in such a way that it takes the previous value of my iteration where I define the initial value.
My function is defined as following:
def Deulab(c, yh1, a, b):
Deulab = c- (EULab(c, yh1, a, b)-1)*0.3
return (Deulab,yh1, a,b)
Output is
Deulab(1.01, 1, 4, 2)
0.9964391705626454
Now I want to iterate keeping yh1, a ,b fixed and start with c0=1 and iterate recursively for c.
The most pythonic way of doing this is to define an interating generator:
def iterates(f,x):
while True:
yield x
x = f(x)
#test:
def f(x):
return 3.2*x*(1-x)
orbit = iterates(f,0.1)
for _ in range(10):
print(next(orbit))
Output:
0.1
0.2880000000000001
0.6561792000000002
0.7219457839595519
0.6423682207442558
0.7351401271107676
0.6230691859914625
0.7515327214700762
0.5975401280955426
0.7695549549155365
You can use the generator until some stop criterion is met. For example, in fixed-point iteration you might iterate until two successive iterates are within some tolerance of each other. The generator itself will go on forever, so when you use it you need to make sure that your code doesn't go into an infinite loop (e.g. don't simply assume convergence).
It sound like you are after recursion.
Here is a basic example
def f(x):
x += 1
if x < 10:
x = f(x)
return x
print (f(4))
In this example a function calls itself until a criteria is met.
CodeCupboard has supplied an example which should fit your needs.
This is a bit of a more persistent version of that, which would allow you to go back to where you were with multiple separate function calls
class classA:
#Declare initial values for class variables here
fooResult = 0 #Say, taking 0 as an initial value, not unreasonable!
def myFoo1(x):
y = 2*x + fooResult #A simple example function
classA.fooResult = y #This line is updating that class variable, so next time you come in, you'll be using it as part of calc'ing y
return y #and this will return the calculation back up to wherever you called it from
#Example call
rtn = classA.myFoo1(5)
#rtn1 will be 10, as this is the first call to the function, so the class variable had initial state of 0
#Example call2
rtn2 = classA.myFoo1(3)
#rtn2 will be 16, as the class variable had a state of 10 when you called classA.myFoo1()
So if you were working with a dataset where you didn't know what the second call would be (i.e. the 3 in call2 above was unknown), then you can revisit the function without having to worry about handling the data retention in your top level code. Useful for a niche case.
Of course, you could use it as per:
list1 = [1,2,3,4,5]
for i in list1:
rtn = classA.myFoo1(i)
Which would give you a final rtn value of 30 when you exit the for loop.

Unscriptable result of generetion function

I have generator function and function that works witn results of the first one. For example:
def gen():
a = 2
b = 3
yield (a, b)
def func():
c = gen()[0]
d = gen()[1]
I have error "'gen()' is unscriptable"
How can I fix it and work with result of func?
You have two problems here.
First, generator objects are not sequences, they're iterators. And you can't index an iterator the way you can a sequence, by subscripting it like [1]. You can loop over them with a for statement or a comprehension, or manually call next on them until they're done, but you can't [1] them.
That's why you get an error message that says the generator object is not subscriptable.
Second, you didn't want to subscript the generator anyway. Your generator yields an iterable of multiple pairs. It happens to only yield once, but that's no different from a sequence with just one pair in it—it's still not the same thing as a pair.
Consider the nearest sequence equivalent:
def seq():
a = 2
b = 3
return [(a, b)]
Obviously seq()[0] is going to be the tuple (2, 3), and seq()[1] is going to be an IndexError. So, even if you could subscript generators, your code wouldn't make sense.
What you actually want to do is either take the first pair, or loop over all the pairs (I'm not sure which). And then you can do [0] and [1] to the/each pair.
So, either this:
def func():
for pair in gen():
c = pair[0]
d = pair[1]
… or this:
def func():
pair = next(gen())
c = pair[0]
d = pair[1]
Or, if you really wanted to call it twice for some reason, this:
def func():
for pair in gen():
c = pair[0]
for pair in gen():
d = pair[1]
… or this:
def func():
c = next(gen())[0]
d = next(gen())pair[1]
What you are trying to do is get the first and second element without iterating over an iterator. You need to iterate over it to get values from it like -
for i in gen():
c, d = i # you need this because you are returning a tuple
You can go through this post to learn more about iterators and generators

Python function that produces both generator and aggregate results

What is the Pythonic way to make a generator that also produces aggregate results? In meta code, something like this (but not for real, as my Python version does not support mixing yield and return):
def produce():
total = 0
for item in find_all():
total += 1
yield item
return total
As I see it, I could:
Not make produce() a generator, but pass it a callback function to call on every item.
With every yield, also yield the aggregate results up until now. I'd rather not calculate the intermediate results with every yield, only when finishing.
Send a dict as argument to produce() that will be populated with the aggregate results.
Use a global to store aggregate results.
All of them don't seem very attractive...
NB. total is a simple example, my actual code requires complex aggregations. And I need intermediate results before produce() finishes, hence a generator.
Maybe you shouldn't use a generator but an iterator.
def findall(): # no idea what your "find_all" does so I use this instead. :-)
yield 1
yield 2
yield 3
class Produce(object):
def __init__(self, iterable):
self._it = iterable
self.total = 0
def __iter__(self):
return self
def __next__(self):
self.total += 1
return next(self._it)
next = __next__ # only necessary for python2 compatibility
Maybe better to see this with an example:
>>> it = Produce(findall())
>>> it.total
0
>>> next(it)
1
>>> next(it)
2
>>> it.total
2
you can use enumerate to count stuff, for example
i=0
for i,v in enumerate(range(10), 1 ):
print(v)
print("total",i)
(notice the start value of the enumerate)
for more complex stuff, you can use the same principle, make produce a generator that yield both values and ignore one in the iteration and use it later when finished.
other alternative is passing a modifiable object, for example
def produce(mem):
t=0
for x in range(10):
t+=1
yield x
mem.append(t)
aggregate=[]
for x in produce(aggregate):
print(x)
print("total",aggregate[0])
in either case the result is the same for this example
0
1
2
3
4
5
6
7
8
9
total 10
Am I missing something? Why not:
def produce():
total = 0
for item in find_all():
total += 1
yield item
yield total

Trying to create generator object but getting function object that doesn't respond to generator calls

I'm trying to write an infinite generator that will repeat every positive integer n times. So for example, if I create f = inf_repeat(3), printing the output of f 10 times would result in:
1 1 1 2 2 2 3 3 3 4
I am close but not quite there. Here's what I've got:
# courtesy of http://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function
# a generator that yields items instead of returning a list
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
def inf_repeat(k):
count_limit = k
#static_var("counter", 0)
#static_var("number", 0)
def func():
while True:
if func.counter == count_limit:
func.counter = 0
func.number += 1
func.counter += 1
yield func.number
return func
My problem is that this doesn't behave entirely like an iterator. The following commands work:
f3 = inf_repeat(3)
print next(f3())
But it's irritating to have to call f3 with parens. I'd like to be able to use the standard iterator syntax I've seen, such as:
print(f3.next())
and
new_list = [iter(f3)]*5
What do I need to modify in my function to get to that point? Looking at a variety of generator tutorials, it seemed that yield was sufficient to create a generator, but clearly that's not the case.
Also I have no objective to using a module. I checked itertools but maybe I missed something that could do what I want without all this code?
You just need to call the generator object (what you called f3) at some point. You can call it when you create it:
f3 = inf_repeat(3)()
or even inside inf_repeat
# change last line to this
return func()
Putting yield in your function makes it a generator function --- that is, a function that, when called, returns a generator. If you want to get the generator, you need to call your generator function at some point.
Incidentally, your implementation is needlessly complex. You can get your desired behavior much more simply without all those decorators and nested functions:
def inf_repeat(k):
number = k
while True:
yield number // k
number += 1
Then:
>>> list(itertools.islice(inf_repeat(3), 10))
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4]
>>> list(itertools.islice(inf_repeat(4), 13))
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4]
Here's a simple solution:
def inf_repeat(N):
i = 1
while True:
for n in range(N):
yield i
i += 1
# Testing:
f = inf_repeat(3)
for j in range(10):
print f.next()
Here's a solution using itertools:
def inf_repeat(N):
return chain.from_iterable(repeat(i, N) for i in count(1))
Another solution using itertools
import itertools as it
def inf_repeat(k):
for i in it.count(1):
for j in [i]*k:
yield j
for n in inf_repeat(3): print n
produces
1
1
1
2
2
2
...
def f(n):
i = 0
while True:
yield i // n
i += 1

calculating current value based on previous value

i would like to perform a calculation using python, where the current value (i) of the equation is based on the previous value of the equation (i-1), which is really easy to do in a spreadsheet but i would rather learn to code it
i have noticed that there is loads of information on finding the previous value from a list, but i don't have a list i need to create it! my equation is shown below.
h=(2*b)-h[i-1]
can anyone give me tell me a method to do this ?
i tried this sort of thing, but that will not work as when i try to do the equation i'm calling a value i haven't created yet, if i set h=0 then i get an error that i am out of index range
i = 1
for i in range(1, len(b)):
h=[]
h=(2*b)-h[i-1]
x+=1
h = [b[0]]
for val in b[1:]:
h.append(2 * val - h[-1]) # As you add to h, you keep up with its tail
for large b list (brr, one-letter identifier), to avoid creating large slice
from itertools import islice # For big list it will keep code less wasteful
for val in islice(b, 1, None):
....
As pointed out by #pad, you simply need to handle the base case of receiving the first sample.
However, your equation makes no use of i other than to retrieve the previous result. It's looking more like a running filter than something which needs to maintain a list of past values (with an array which might never stop growing).
If that is the case, and you only ever want the most recent value,then you might want to go with a generator instead.
def gen():
def eqn(b):
eqn.h = 2*b - eqn.h
return eqn.h
eqn.h = 0
return eqn
And then use thus
>>> f = gen()
>>> f(2)
4
>>> f(3)
2
>>> f(2)
0
>>>
The same effect could be acheived with a true generator using yield and send.
First of, do you need all the intermediate values? That is, do you want a list h from 0 to i? Or do you just want h[i]?
If you just need the i-th value you could us recursion:
def get_h(i):
if i>0:
return (2*b) - get_h(i-1)
else:
return h_0
But be aware that this will not work for large i, as it will exceed the maximum recursion depth. (Thanks for pointing this out kdopen) In that case a simple for-loop or a generator is better.
Even better is to use a (mathematically) closed form of the equation (for your example that is possible, it might not be in other cases):
def get_h(i):
if i%2 == 0:
return h_0
else:
return (2*b)-h_0
In both cases h_0 is the initial value that you start out with.
h = []
for i in range(len(b)):
if i>0:
h.append(2*b - h[i-1])
else:
# handle i=0 case here
You are successively applying a function (equation) to the result of a previous application of that function - the process needs a seed to start it. Your result looks like this [seed, f(seed), f(f(seed)), f(f(f(seed)), ...]. This concept is function composition. You can create a generalized function that will do this for any sequence of functions, in Python functions are first class objects and can be passed around just like any other object. If you need to preserve the intermediate results use a generator.
def composition(functions, x):
""" yields f(x), f(f(x)), f(f(f(x)) ....
for each f in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
yield x
Your specs require a seed and a constant,
seed = 0
b = 10
The equation/function,
def f(x, b = b):
return 2*b - x
f is applied b times.
functions = [f]*b
Usage
print list(composition(functions, seed))
If the intermediate results are not needed composition can be redefined as
def composition(functions, x):
""" Returns f(x), g(f(x)), h(g(f(x)) ....
for each function in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
return x
print composition(functions, seed)
Or more generally, with no limitations on call signature:
def compose(funcs):
'''Return a callable composed of successive application of functions
funcs is an iterable producing callables
for [f, g, h] returns f(g(h(*args, **kwargs)))
'''
def outer(f, g):
def inner(*args, **kwargs):
return f(g(*args, **kwargs))
return inner
return reduce(outer, funcs)
def plus2(x):
return x + 2
def times2(x):
return x * 2
def mod16(x):
return x % 16
funcs = (mod16, plus2, times2)
eq = compose(funcs) # mod16(plus2(times2(x)))
print eq(15)
While the process definition appears to be recursive, I resisted the temptation so I could stay out of maximum recursion depth hades.
I got curious, searched SO for function composition and, of course, there are numerous relavent Q&A's.

Categories