开发者

Python Yield Statement does not appear to continue where it left off

开发者 https://www.devze.com 2023-03-12 09:17 出处:网络
I must be overlooking the obvious, but I cannot for the life of me figure out why this yield statement does not cont开发者_StackOverflow社区inually give me a new datetime value that is 15 minutes late

I must be overlooking the obvious, but I cannot for the life of me figure out why this yield statement does not cont开发者_StackOverflow社区inually give me a new datetime value that is 15 minutes later than the previous one. The gettime function is behaving more like a function that "returns" rather than "yields".

import datetime

#function that continually adds 15 minutes to a datetime object
def gettime(caldate):
    while True:
        yield caldate
        caldate += datetime.timedelta(minutes=15)

#initialize a datetime object
nextdate = datetime.datetime(2011, 8, 22, 11,0,0,0)

#call gettime function 25 times.
for i in range(0,25):
    print gettime(nextdate).next()


#output feels like it should be a series of incrementing datetime values 15 minutes apart.
#in actuality, the same result namely:

#2011-08-22 11:00:00

#happens 25 times.


It's because you're calling the generator each time, starting it anew.

Here is a fixed version:

dates = gettime(nextdate)
for i in range(0, 25):
    print dates.next()   # note that you're not initializing it each time here
                         # just calling next()

That gives me:

2011-08-22 11:00:00
2011-08-22 11:15:00
2011-08-22 11:30:00
2011-08-22 11:45:00
...etc.

An important thing to remember is that a function that yields actually returns a generator, as you can see when we look at my dates object:

>>> dates
<generator object gettime at 0x02A05710>

This is what you can repeatedly call next() on to get the next value. Each time you executed your loop, you were creating a whole new generator and getting the next (in this case, first) value out of it.


Daniel already pointed out that you are creating a fresh generator each time through your loop. It is more usual to loop over a generator, or have another generator consume it, than to explicitly call next() every time.

Here is how you could loop over an islice() of your generator.

from itertools import islice
import datetime

#generator that continually adds 15 minutes to a datetime object
def gettime(caldate):
    while True:
        yield caldate
        caldate += datetime.timedelta(minutes=15)

#initialize a datetime object
nextdate = datetime.datetime(2011, 8, 22, 11,0,0,0)

#call gettime function 25 times.
for the_date in islice(gettime(nextdate),0,25):
    print the_date

You can also simplify this to a generator expression if you wish

from itertools import islice, count
import datetime

#initialize a datetime object
nextdate = datetime.datetime(2011, 8, 22, 11,0,0,0)

#generator expression that continually adds 15 minutes to a datetime object
gettime = (nextdate+datetime.timedelta(minutes=15*i) for i in count())

#call gettime function 25 times.
for the_date in islice(gettime,0,25):
    print the_date


Using print_function:

print(*[i[0] for i in zip(gettime(nextdate), range(25))], sep='\n')

But you may want to have just the list.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号