昨天看了许多条博客,同时问了大佬一些心中的疑惑,对这个yield心中有了些许的理解,虽然可能没有理解到他的内涵,但至少在使用时该如何使用还是有了些许了解,因此决定写出来分享
首先我们得了解一个东西叫迭代器,通常的for…in…循环中,in后面是一个数组,这个数组就是一个可迭代对象,类似的还有链表,字符串,文件。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。 它的缺陷是所有数据都在内存中,如果有海量数据的话将会非常耗内存。他们可以从内容从中一个一个的读取,这就是迭代。
接着我们需要了解迭代器里的一个特殊——生成器,生成器也是一个可以迭代的对象,但是生成器每个只能迭代一次(至于为什么后面会讲),这是他特殊的原因。因为用的时候才生成。比如 mygenerator = (x*x for x in range(3)),注意这里用到了(),它就不是数组,而上面的例子是[]。生成器这里用的是小括号,而迭代器用的是中括号。
好了接下来得讲下他们的方法,不管是生成器还是迭代器,都可以使用他的方法,就是next(这个方法在python2里面是使用的时候是方法c.next(),在python3里面变为了函数next(c)),但是由于迭代器可以自动进行,相当于里面已经内嵌了这个方法,生成一个迭代器他可以自动往后迭代,但是生成器不一样,生成一个生成器的时候,他是定在初始状态的,这就需要我们的next来一步一步推动他们。他们还有一种方法是send(),这个相当于在next功能的基础上,再加了一个传递的功能,他可以传递参数给yield表达式,所以send(None)就相当于next参数。
现在我们可以来谈谈yield了,其实yield就相当于一个return,只是return返回的是值,但是yield返回的是生成器,除了这点其他都一样,所以return也好yield也好都只能用在函数中,不要出现这种代码了:
for i in range(5): return i
所以要试验yield要在函数里实验,我们可以试着构造一个生成器:
def y_test(x): for i in range(x): yield i print(i) y_test(3)
我们试着输出结果,却发现没有输出,这是因为生成了一个生成器,而且生成的生成器是在初始状态,咱们还没给他下指令他就不会开始生成,所以现在我们给他一个指令
def y_test(x): for i in range(x): yield i print(i) y_test(3) c = y_test(3) next(c)
诶,我们现在改造了后为什么还是显示没有输出,现在生成器是生成了但别忘了这是一个相当于return的函数,他实际上已经把值传进了内存,但是没有显示出来,我们可以用一个print把他显示出来
def y_test(x): for i in range(x): yield i print(i) y_test(3) c = y_test(3) print(next(c))
现在我们就会看到它显示出来了(range这个函数生成了从1到n-1得数,比如range(5)生成了0.1.2.3.4)
好,那么接下来你可能又会有问题了,为什么这个只生成了第一个数啊,不应该是遍历把所有的输出来吗,这就是yield的作用了,这是因为生成了生成器,我们next他一次,他也就只会往前走一次,第二次就不走了,那我们就再来一次next看看会怎样:
def y_test(x): for i in range(x): yield i print(i) y_test(3) c = y_test(3) print(next(c)) print(next(c))
这时候出现了三个值,这就要继续解释yield的原因了,每次我们使用一次next,他都会执行到第一个yield结束的位置,第二次用next推动他执行时,他就会从上一个yield执行完成的位置开始执行到下一个yield执行完成,在这里是在for循环里,下一个yield就是第二个循环里的yield,虽然是一样的语句,但是他们所在的循环次数不一样,所以yield就相当于返回值的同时,记住当前运行到的位置,下一次运行就从上一次运行到的位置开始运行,这也是为什么他只能遍历一遍的原因,因为在第二个next执行的时候,第一个next里的内容已经被抛掉了,内存里只有第二个yield执行的内容。
我们可以再看一例子来加深理解:
def f(x): for i in range(x): yield i print (i) yield i+1 c = f(5) print(next(c)) print(next(c)) print(next(c))
根据上文的理解会输出四个值
符合前面的猜想,最后让我们来用一个斐波那契数列的例子来结束全文吧:
def fib(x): yield 1 a,b = 1,1 while x: a,b = b,a+b yield a x=x-1 for i in fib(5): print(i) >>>runfile('F:/Python/exercise/pygame/yield_text.py', wdir='F:/Python/exercise/pygame') 1 1 2 3 5 8