Python Yield Statement似乎没有从它停止的地方继续

时间:2011-06-10 02:05:26

标签: python yield

我必须忽略显而易见的事情,但我不能为我的生活弄清楚为什么这个yield语句不会持续给我一个比前一个晚15分钟的新日期时间值。 gettime函数的行为更像是“返回”而不是“yield”的函数。

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.

3 个答案:

答案 0 :(得分:15)

这是因为你每次都在调用发生器,重新启动它。

这是一个固定版本:

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()

这让我:

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.

要记住的一件重要事情是yield实际上返回生成器的函数,就像我们查看dates对象时所看到的那样:

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

这是您可以反复调用next()以获取下一个值的内容。每次执行循环时,您都创建了一个全新生成器并从中获取下一个(在本例中为第一个)值。

答案 1 :(得分:3)

丹尼尔已经指出你每次通过循环创建一个新的生成器。循环生成器或让另一个生成器使用它比通常每次显式调用next()更常见。

以下是如何循环生成器的islice()。

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

如果您愿意,也可以将其简化为生成器表达式

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

答案 2 :(得分:0)

使用print_function:

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

但你可能只想要清单。