python中yield的用法

时间:2021-09-07 23:29:14

昨天看了许多条博客,同时问了大佬一些心中的疑惑,对这个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)

python中yield的用法

好,那么接下来你可能又会有问题了,为什么这个只生成了第一个数啊,不应该是遍历把所有的输出来吗,这就是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))

 

python中yield的用法

这时候出现了三个值,这就要继续解释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)) 

根据上文的理解会输出四个值

python中yield的用法

符合前面的猜想,最后让我们来用一个斐波那契数列的例子来结束全文吧:

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