我试图了解收益率是如何工作的,在我读完这篇文章后,我相信它是可以理解的.
但是我仍然不明白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
Run Code Online (Sandbox Code Playgroud)
我认为当我有一个生成器(一个当时返回单个参数但返回尽可能多的参数直到它到达结束的函数)时,yield会起到这样的作用:"好吧,让我们回复这个论点,但也许我们仍然可以返回另一个".但是在我的示例中,我没有任何生成器,yield"返回"一个列表,并以某种方式访问list的迭代器.我完全不知道发生了什么.
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
>>>
Run Code Online (Sandbox Code Playgroud)
__iter__当需要在对象的内容上的迭代器时(如在它是for x in obj构造的一部分时),在对象上调用.您可以使用yield创建生成器(因为生成器是迭代器),但在本示例中您不需要.以下内容也适用:
def __iter__(self):
return iter(self.__a)
Run Code Online (Sandbox Code Playgroud)
如果要使用yield,并且希望Vect对象的迭代器遍历向量的内容,则必须单独生成每个值:
def __iter__(self):
for i in self.__a:
yield i
Run Code Online (Sandbox Code Playgroud)
在yield该方法__iter__会返回一个发电机,并调用next()发电机对象将在其最后一次离开,因为它通过迭代点恢复功能__a.
=======
在回答有关Python如何跟踪生成器执行位置的附加问题时,我相信它使用了生成器的gi_frame属性的f_lasti(=="last instruction")(Generators,与普通函数不同,带有一个与他们一起执行的框架).这里有一些工具可以显示值如何变化:
>>> import dis
>>> def g():
... yield 1
... for i in range(10):
... yield i*2
...
>>> gen = g()
>>> dis.dis(gen.gi_code)
2 0 LOAD_CONST 1 (1)
3 YIELD_VALUE
4 POP_TOP
3 5 SETUP_LOOP 29 (to 37)
8 LOAD_GLOBAL 0 (range)
11 LOAD_CONST 2 (10)
14 CALL_FUNCTION 1
17 GET_ITER
>> 18 FOR_ITER 15 (to 36)
21 STORE_FAST 0 (i)
4 24 LOAD_FAST 0 (i)
27 LOAD_CONST 3 (2)
30 BINARY_MULTIPLY
31 YIELD_VALUE
32 POP_TOP
33 JUMP_ABSOLUTE 18
>> 36 POP_BLOCK
>> 37 LOAD_CONST 0 (None)
40 RETURN_VALUE
>>> gen.gi_frame.f_lasti ## -1 because we haven't started yet
-1
>>> gen.next()
1
>>> gen.gi_frame.f_lasti
3
>>> gen.gi_frame.f_locals
{}
>>> gen.next()
0
>>> gen.gi_frame.f_lasti , gen.gi_frame.f_locals
(31, {'i': 0})
>>> gen.next()
2
>>> gen.gi_frame.f_lasti , gen.gi_frame.f_locals
(31, {'i': 1})
>>>
Run Code Online (Sandbox Code Playgroud)
请注意f_lasti值如何与反汇编代码中最后一个yield产生的编号行相对应:当重新输入生成器时,它将从该点重新开始.