【发布时间】:2017-11-18 14:04:51
【问题描述】:
看了answer1和answer2之后,yield的目的还是不清楚。
在第一种情况下,使用以下函数,
def createGenerator():
mylist = range(3)
for i in mylist:
yield i*i
在下面调用createGenerator,
myGenerator = createGenerator()
应该返回collections.abc.Generator类型的对象(如(x*x for x in range(3))),is-a collections.abc.Iterator & collections.abc.Iterable
遍历myGenerator对象并获得第一个值(0),
next(myGenerator)
实际上会使createGenerator 函数的for 循环在内部调用__iter__(myGenerator) 并检索collections.abc.Iterator 类型对象(obj(say))然后调用__next__(obj) 以获取第一个值(0 ) 之后是使用 yield 关键字的 for 循环的暂停
如果这个理解(以上)是正确的,那么,
那么,下面的语法(第二种情况),
def createGenerator():
return (x*x for x in range(3))
myGen = createGenerator() # returns collections.abc.Generator type object
next(myGen) # next() must internally invoke __next__(__iter__(myGen)) to provide first value(0) and no need to pause
不足以达到相同的目的(上图)并且看起来更具可读性?两种语法记忆都不是有效的吗?如果是,那么,我应该什么时候使用yield 关键字?是否存在必须使用yield 的情况?
【问题讨论】:
-
生成器表达式是理解结构。它们对您可以在其中执行的操作类型有更多限制。例如,您不能有复合语句。有一些方法可以解决这个问题,但我认为这类似于“我什么时候应该使用 for 循环”与“我什么时候应该使用理解”。使用当时更具可读性的一种,或者让您的生活更轻松的一种。
-
当您没有统一的数据要返回时会发生什么?是的,当你的生成器只是一个围绕迭代器的美化包装器时,你不需要 yield,但通常情况并非如此。
-
不,一点也不。我发现
yield语法 very 清晰。 -
尝试让
createGenerator返回的东西在每次调用next时都接受新的信息,然后你就会明白为什么会有yield存在。在您给出的示例中,您知道在编写代码时希望生成器吐出的东西,但有时(通常)您需要能够将东西传递到生成器中,让它计算一些东西,然后产生新计算的东西。 -
同样的原因我们有
def,而不是尝试用lambda编写我们所有的函数。同样的原因,我们不会使用列表理解创建每个列表。 Genexp 在语法上非常有限;他们不能表达太多。
标签: python python-3.x generator yield coroutine