Python生成器

一、什么是生成器?

在python中,使用了yield的函数被称为生成器,生成器返回的是一个迭代器的函数,只能用于迭代操作,在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值,并在下一次执行next()方法时从当前位置继续运行。

生成器应用实例,利用生成器输出1—1亿的数。

list = (i for i in range(1,100000000))
for item in list:
    print(item)

二、如何创建一个生成器?如何使用生成器?

(1)使用函数创建

    1.函数内部需要实现一个循环体,并实现返回值推导算法,并由yield返回每次推导出来的值

    2.yield关键词,其核心作用是

                          1.类似return,将指定值或多个值返回给调用方

                          2.记录此次返回或遍历的位置,返回数值之后,挂起,直到下一次执行next函数                              再重新从挂起点接着运行(类似于断点)

def fib(max):
    a, b = 1, 1
    while a < max:
        yield a  # generators return an iterator that returns a stream of values.
        a, b = b, a + b


for n in fib(15):
    print(n)

运行结果:

(2)使用生成器推导式

核心点如下:

        1.整体规律,类似类表生成推导式

        2.只是语法,由之前的[ ],变成()

# 使用推导式,对于小于10的,乘3,对于大于等于10的,乘5
# 此时返回的不再是列表,而是一个生成器
g=(i*3 if i<10 else i*5 for i in range(100))

运行结果:

三、yield与return对比

1.相同点:

        (1)均在函数体内使用,并且向调用方返回结果

        (2)均可返回一个值或者多个值,如果是多个值,则是以元组格式返回

2.不同点:

       1.包含yield的函数,调用时最终返回的是一个生成器,单纯的return函数,调用时返回的是一         个值。

       2.return执行并返回值后,便会退出函数体,该函数体内存空间即回收释放

       3.yield执行并返回值后,不会退出函数体,而是挂起,待下次next时,再从挂起点恢复运行

       4.yield语句可以接受通过生成器send()方法传入的参数并赋值给一个变量,以动态调整生成器         的行为表现

        5.yield语句的返回值,可以通过from关键词指定返回源

3.return在生成器中的作用:

        1.在一个生成器函数中,如果没有return,则默认执行至函数完毕,如果在执行过程中                     return,则直接抛出StopIteration终止迭代。

#1、yield和return共存
def gene(maxcount):
    a,b=0,1
    count=1
    while True:
        if count>maxcount:
            #直接退出函数体
            return 
        else:
            #返回值后,函数在该处挂起,下次再从该处恢复运行
            yield a+b
            a,b=b,a+b
            count+=1
 
#2、yield接受通过send传入的参数并动态调整生成器行为
#
def gene(maxcount):
    a,b=0,1
    count=1
    while True:
        if count>maxcount:
            return 
        else:
            msg=yield a+b
            if msg=='stop':
                return
            a,b=b,a+b
            count+=1
g=gene(10)
next(g)
g.send('msg') #生成器终止,并抛出一个StopIteration异常
 
#3、通过from关键词,接受另外一个生成器,并通过该生成器返回值
#此处只是做展示,大家知道即可,后续如果有类似场景,可以想起来可以这么搞就行
gene1=(i for i in range(10))
def gene2(gene):
    yield from gene
g=gene2(gene1)

四、基本应用举例

      (1)可控文件读取

def read_file(fpath): 
    BLOCK_SIZE = 1024 
    with open(fpath, 'rb') as f: 
        while True: 
            block = f.read(BLOCK_SIZE) 
            if block: 
                yield block 
            else: 
                return

      (2)协程

       进程、线程和协程的概念:

        1.进程指单独的一个CPU运行程序,可以简单认为一个进程就是一个独立的程序

        2.线程是操作系统能够进行运算调度的最小单位。它被包含在进程中,是进程中的实际运作单位

        3.协程可以认为是同一个线程内运行的代码

        4.进程包含线程,线程包含协程

        5.进程、线程的切换和调度,一般由操作系统自动完成,具体调度和切换机制较为复杂

        6.同一线程下,多个协程的切换是由自己编写的代码进行控制,可以实现个性化的调度和切换需求

        协程的特点:

        1.协程是非抢占式特点:协程也存在着切换,这种切换是由我们用户来控制的。协程主解决的是IO的操作
        2.协程有极高的执行效率:因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显
        3.协程无需关心多线程锁机制,也无需关心数据共享问题:不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多

        协程借助生成器实现的基本思路:

        1.因为生成器通过yield,可以挂起,待下次执行时再次从挂起点恢复运行,满足切换和交替运行的特点

        2.因为生成器可以通过send函数,动态的干预指定生成器的功能和表现,为实现多个协程之间协作提供了可能

#让两个函数交替运行
#核心就是把两个正常的函数使用yield变为生成器函数,然后交替使用其next调用即可
def task1(times):
	for i in range(times):
		print('task1 done the :{} time'.format(i+1))
		yield
def task2(times):
	for i in range(times):
		print('task2 done the :{} time'.format(i+1))
		yield	
gene1=task1(5)
gene2=task2(5)
for i in range(100):
	next(gene1)
	next(gene2)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值