为什么yield会返回迭代器?

时间:2011-07-23 23:13:56

标签: python yield

我试图理解收益率是如何运作的,在我读完之后text我相信它是可以理解的。

但是我仍然不明白yield和__iter__之间的联系是什么,因为我刚刚发现这段代码有效:

class Vect():
    def __init__(self, *args):
        self.__a = list(args)
    def print_(self):
        print self.__a
    def __iter__(self):
        yield self.__a

asd = Vect(1,2,3,4,5)
for foo in asd:
    print foo

我认为当我有一个生成器(一个当时返回单个参数但返回尽可能多的参数直到它结束的函数)时,yield会像:“好的,让我们返回这个参数,但也许我们仍然可以返回另一个“。但是在我的示例中,我没有任何生成器,yield“返回”一个列表,并以某种方式访问​​list的迭代器。我完全不知道发生了什么。

3 个答案:

答案 0 :(得分:9)

yield返回传递给它的任何对象,即使该对象是序列或生成器或其他迭代器。因此:

>>> def g():
...     yield [1,2,3]
...     yield 1
...     yield 2
...     yield 3
... 
>>> gen = g()
>>> gen.next()
[1, 2, 3]
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
3
>>> gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>
当需要在对象内容上的迭代器时(如在它是__iter__构造的一部分时),在对象上调用

for x in obj。您可以使用yield来创建生成器(因为生成器是迭代器),但在本示例中您不需要。以下内容也适用:

def __iter__(self):
   return iter(self.__a)

如果要使用yield,并且希望Vect个对象的迭代器移动向量的内容,则必须单独生成每个值

def __iter__(self):
    for i in self.__a:
        yield i

yield表示__iter__将返回一个生成器,并且在生成器对象上调用next()将在它最后一次停止的位置恢复该函数,因为它遍历{ {1}}。

=======

在回答有关Python如何跟踪生成器执行位置的其他问题时,我相信它使用了生成器的gi_frame属性的f_lasti(==“last instruction”)(Generators,与普通函数不同) ,随身携带一个执行框架)。这里有一些工具可以显示值的变化:

__a

注意f_lasti值如何对应于反汇编代码中最后一个yield产生的编号行:当重新输入生成器时,它会从该点重新开始。

答案 1 :(得分:1)

yield完全按照你的理解工作 - 它返回一个对象,在你的情况下是一个列表。

也许这会让它更清晰 - 将代码更改为:

i = 1
for foo in asd:
    print i
    i += 1
    print foo

正如您所看到的,只有一次迭代 - 迭代器包含一个元素 - 列表[1,2,3,4,5]。

答案 2 :(得分:1)

如果您检查打印件,您会看到 iter 整个列表都会返回,当您打印foo时,它只打印一次

检查一下:

for index, foo in enumerate(asd):
    print index, foo