Function that always keep returning new data - python

I'm kind of a new to python and i'm trying to run a code for a program, but i'm stuck in this part where i need a Function that always keep returning new data, here's a part of the code that always keep returning a zeros!
import time
def forloop():
for i in range(0,10000):
return i
while True:
time.sleep(0.25)
print(forloop())

When you call forloop() and do return i inside it, it returns from the function, and the next time you call forloop() it will start from the beginning. What you want to use are generator functions
You can use generator functions for this (using yield statement) to yield the values instead of return .
Example -
def forloop():
for i in range(0,10000):
yield i
x = forloop()
while True:
try :
time.sleep(0.25)
print(next(x))
except StopIteration:
x = forloop()
next(x) throws StopIteration exception if the generator has been exhausted, in which case we catch that exception and recreate the generator.

Your function returns immediately, and each time you call it you start at 0 again.
You can do what you want with a regular function; use a global and keep incrementing that:
_counter = -1
def increasing():
global _counter
_counter += 1
return counter
but a better idea would be to use a generator function:
def increasing():
counter = 0
while True:
yield counter
counter += 1
and you can use that in a loop:
for count in increasing():
print(count)
time.sleep(0.25)
The standard library already includes such a generator: the itertools.count() function does just that. Together with the next() function you can pretty much recreate your while loop:
from itertools import count
counter = count()
while True:
time.sleep(0.25)
print(next(counter))
If you wanted to continually loop over the the values 0 through to 9999, then you'd write a custom generator function that does just that:
def count_to_9999_and_restart():
while True:
for i in range(10000):
yield i
and you can use that generator:
counter = count_to_9999_and_restart()
while True:
time.sleep(0.25)
print(next(counter))

Try using a global variable to keep track of where the function reached inbetween calls:
counter = 0
def forloop():
global counter
counter += 1
return counter

Related

returning value of for loop in python from one function to another

I want to achieve this
for i in range(1,10):
print(i)
but using different functions, by putting values of for-loop to variable named valuee and then as an argument to clamp function then printing it. Why am I getting just 1? and not from 1->9?
def clamp(valuee):
print(valuee)
def value():
for i in range(1,10):
return i
valuee=value()
clamp(valuee)
If you use return you will end the function. You are looking for a generator; just change the return for yield.
def clamp(valuee):
print(valuee)
def value():
for i in range(1,10):
yield i
You can use your generator in 2 ways: inside a loop
for valuee in value():
clamp(valuee)
Or as you originally wanted, but you have to add the keyword next:
def clamp(valuee):
print(valuee)
def value():
for i in range(1,10):
yield i
valuee = value()
clamp(next(valuee))
clamp(next(valuee))
clamp(next(valuee))
...
It is not printing all the values because in value() method you are using return and when i=1 in loop, value() returns 1 and exits from the function and loop too.
you can use ...
def clamp(valuee):
print(valuee)
def value():
for i in range(1,10):
clamp(i)
value()

Create a function that will increment by one when called

I am needing a function that will increment by one every time it is called. I have used count but every time I do it resets the count back to the original value plus one count. I have seen lots of code but none of it works. Here is what I have now
I have done lots of looking into loops and iterations
def count_row():
count = 1
while count >= 1:
yield count
count += 1
return count
You can use itertools.count.
from itertools import count
counter = count(1)
next(counter) # 1
next(counter) # 2
Stateful function
If you absolutely want a stateful function instead of calling next, you can wrap the count in a function.
def counter(_count=count(1)):
return next(_count)
counter() # 1
counter() # 2
Class
Alternatively, itertools.count being a class, you can inherit from it to extend it's behaviour and make it a callable.
class CallableCount(count):
def __call__(self):
return next(self)
counter = CallableCount(1)
counter() # 1
counter() # 2
Using a class would be my preferred approach since it allows instantiating multiple counters.
You need a closure. Define a function make_counter which initializes a local variable, then defines and returns a function that increments that variable on each call.
def make_counter():
count = -1
def _():
count += 1
return count
return _
count_row = make_counter()
Now count_row will return a new value on each call:
>>> count_row()
0
>>> count_row()
1
This is sort of the dual of a class. You have a function that "wraps" some data (closes over the variable), instead of a piece of data with an associated method. The class version; note the similarity to make_counter:
class Count:
def __init__(self):
self.count = -1
def __call__(self):
self.count += 1
return count
An instance of this class now behaves like our previous closure.
>>> count_row = Count()
>>> count_row()
0
>>> count_row()
1
You can use a generator here that increments value by one every time it's called using next():
def count_row():
count = 0
while True:
count += 1
yield count
itr = count_row()
print(next(itr)) # 1
print(next(itr)) # 2
If you look closely, this is equivalent to what itertools.count() does.
if I got this right this should work:
count=0
def count_row(count):
count += 1
return count

How to pass values to a generator in a for loop?

I know that you can use .send(value) to send values to an generator. I also know that you can iterate over a generator in a for loop. Is it possible to pass values to a generator while iterating over it in a for loop?
What I'm trying to do is
def example():
previous = yield
for i range(0,10):
previous = yield previous*i
t = example()
for value in example"...pass in a value?...":
"...do something with the result..."
You technically could, but the results would be confusing. eg:
def example():
previous = (yield)
for i in range(1,10):
received = (yield previous)
if received is not None:
previous = received*i
t = example()
for i, value in enumerate(t):
t.send(i)
print value
Outputs:
None
0
2
8
18
Dave Beazley wrote an amazing article on coroutines (tldr; don't mix generators and coroutines in the same function)
Ok, so I figured it out. The trick is to create an additional generator that wraps t.send(value) in a for loop (t.send(value) for value in [...]).
def example():
previous = yield
for i in range(0,10):
previous = yield previous * i
t = examplr()
t.send(None)
for i in (t.send(i) for i in ["list of objects to pass in"]):
print i

generator is yielded but the the yielded variable is not printed

While using generators, we yield a variable whose value is saved and will resume with that saved value when we give the next() statement. Is there a way where we can do this but not actually print the value of the yielded variable?
def foo():
n = 0
print("This is where we start")
yield n
n += 1
print("This is first")
yield n
n += 1
print("This is second")
yield n
a = foo()
next(a)
This is where we start
0
next(a)
This is first
1
This is a very naive way of using generators(implementing them) and doesn't show their effectiveness.
I know that this can also be done using iterators where the value won't be printed, but just wondering if it can be done with generators.
You are using the Python interactive interpreter to call next(), and it is a function of that shell to print return values. What you are seeing has nothing to do with generators.
Simply assign the return value of the next() call to variable to not have them echoed:
ignored = next(a)
or run your code as a script.
Note that generators are paused immediately; no code inside is run until you call next() on it. At that point the code runs until a yield expression is reached; it's value is returned and the generator is paused again. At no point is the yield result 'saved'.

Returning generator from a function

I'm slowly getting to wrap my head around Python generators.
While it's not a real life problem for now, I'm still wondering why I can't return a generator from a function.
When I define a function with yield, it acts as a generator. But if I define it inside another function and try to return that instead, I get an ordinary function, i.e. not a generator with next method.
In other words, why the give_gen() approach in code below does not work?
#!/usr/bin/python
import time
def gen(d):
n = 0
while True:
n = n + d
time.sleep(0.5)
yield n
def give_gen(d):
def fn():
n = 0
while True:
n = n + d
time.sleep(0.5)
yield n
return fn
if __name__ == '__main__':
g = give_gen(3) # does not work
g = gen(3) # works well
while True:
print g.next()
# AttributeError: 'function' object has no attribute 'next'
# in case of give_gen
Why can't I return a generator from a function?
A generator function returns a generator only when called. Call fn to create the generator object:
return fn()
or call the returned object:
g = give_gen(3)()
You did call gen(); had you referred to just gen without calling it you'd have a reference to that function.

Categories