Infinite yield problem
Here is my simple code
class Fibonacci:
@staticmethod
def series():
fprev = 1
fnext = 1
yield fnext
while True:
yield fnext
fprev,fnext = fnext,fprev+fnext
under10 = (i for i in Fibonacci.series() if i<10)
for i in under10 :
print i
It's absolutely obvious, but...WHY interpreter is executing block
while True:
yield fnext
fprev,fnext = fnext,fprev+fnext
Forever? I specified in generator,that I want only elements<10
under10 = (i for i in Fibonacci.series() if i<10)
IMHO, it's a little bit misunderstanding Any way to prevent infinite execution without re-writing "series"?开发者_如何学Python
How should the interpreter know that all future numbers will be < 10? It would have to either know (somehow) that it’s churning out the Fibonacci series, or it would have to inspect the whole series.
It can’t do the first, so it does the second.
You can fix this by using itertools.takewhile
:
import itertools
under10 = itertools.takewhile(lambda n: n < 10, Fibonacci.series())
under10 = (i for i in Fibonacci.series() if i<10)
Will keep going, it just won't yield values greater than 10. There's nothing instructing the for loop to stop.
You would probably have better luck doing something like:
for i in Fibonacci.series():
if i > 10:
break
#do your appends and such here
EDIT:
I like Konrad's itertools example much more, I always forget about itertools
The infinite loop isn't a result of the while True:
in the Fibonacci.series()
method. It's caused by the under10 = (i for i in Fibonacci.series() if i<10)
generator which just keeps going since it doesn't realize the values yielded will never get smaller. Here's [another] way to fix it and generalize it at the same time -- without re-writing series()
-- using the itertools.takewhile()
iterator:
import itertools
fibos_under = lambda N: itertools.takewhile(lambda f: f < N, Fibonacci.series())
for i in fibos_under(10):
print i
BTW: You can simplify the Fibonacci.series()
method slightly by changing it to this which yields the same values:
class Fibonacci:
@staticmethod
def series():
fprev,fnext = 0,1
while True:
yield fnext
fprev,fnext = fnext,fprev+fnext
精彩评论