I must be overlooking the obvious, but I cannot for the life of me figure out why this yield statement does not continually 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 yield
s 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With