我试图理解收益率是如何运作的,在我读完之后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的迭代器。我完全不知道发生了什么。
答案 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