python3.8 三利器之 生成器

python生成器

生成器的使用场景:
通常创建了一个数据量很大的,如一百万个元素的数据,需要很大的存储空间,而我们通常仅仅需要其中的几百个或几个,而其他用不上的数据则比较占用空间,这时就需要用到生成器

  1. 生成器是特殊的迭代器
  2. 生成器只存储算法,不存储数据
  3. 生成器是一边循环一边执行的计算机制
  4. 主要作用:节省内存,提高算法效率

生成器的第一种写法(简易版)

g = (x for x in range(10))

从collections包中导入Iterable,Iterator
判断g的数据类型

print(isinstance(g,Iterator)) >>>True
print(isinstance(g,Iterable)) >>>True

都返回True,说明生成器既可以迭代,同时也是一种特殊的迭代器
可以通过next()方法唤醒生成器

print(next(g)) >>> 0
print(next(g)) >>> 1
print(next(g)) >>> 2
...

使用next()方法超出范围后,会报错 StopIteration
可用for循环去迭代,因为for循环可以自动捕获StopIteration,然后跳出,不会报错,所以通常使用for循环去迭代生成器

for i in g:
    print(i)

第二种生成器写法(用于复杂算法)

使用生成器实现斐波那契数列(兔子问题)

def FB(month):
    m = 0
    a, b = 0, 1
    while m < month:
        yield b # yield 是区别函数和生成器的关键字
        a, b = b, a + b
        m += 1
        
# 一旦函数中存在有yield关键字,这个函数就是一个生成器

yield的简单理解:

yield是时停版的“return”,既具有return的返回功能,同时附加了时停的替身,每当程序运行到yield的位置时,都会先返回yield后面的值,然后暂停函数,下一次继续调用函数的时候,从yield的后面开始运行

yield生成器函数的取值 注意点

在使用next()或者__next__方式取值的时候,需要注意函数的引用问题,如果不先将函数赋值给其他变量,会导致无论打印多少次出来的值都是同一个值,如下所示:

	# 不赋值变量,直接打印数据,所有结果均为1
	# 相当于每一次都重新启用FB()函数,然后往里面传值
	print(next(FB(9)))			>>> 1
    print(next(FB(9)))			>>> 1
    print(next(FB(9)))			>>> 1
    print(next(FB(9)))			>>> 1
    print(next(FB(9)))			>>> 1
    print(next(FB(9)))			>>> 1
    print(FB(9).__next__())		>>> 1
    print(FB(9).__next__())		>>> 1
    print(FB(9).__next__())		>>> 1
    print(FB(9).__next__())		>>> 1
    print(FB(9).__next__())		>>> 1
    print(FB(9).__next__())		>>> 1
    print(FB(9).__next__())		>>> 1
    ...

将函数赋值给变量后,再使用next()或__next__方法打印数据

	#将FB(9)赋值给变量a后,再打印数据
	a = FB(9)
    print(next(a)) 	>>> 1
    print(next(a))	>>> 1
    print(next(a))	>>> 2
    print(next(a))	>>> 3
    print(next(a))	>>> 5
    print(next(a))	>>> 8
    print(next(a))	>>> 13
    ...

多个yield的用法

def sendTest():

    while True:
        v = yield 'hello world'
        r = yield v
        a = yield r
        yield a


if __name__ == '__main__':
    test = sendTest()
    print(test.__next__()) # 返回第一个yield后面的'hello world'
    print(test.__next__()) # 第一个yield抛出'hello world'后,为None,赋值给v,第二个yield返回None
    print(test.__next__())# 同上
    print(test.__next__())# 同上

# 输出结果
 	>>> hello world
	>>> None
	>>> None
	>>> None

使用yield关键字的函数,配合send()方法,还支持从外部传入参数进去

                              
def sendTest():               
               
    while True:               
        v = yield 'hello world
        r = yield v   # 当第二个print执行的时候,send传送的‘空条承太郎’会赋值给 v,所以第二个yield抛出‘空条承太郎’后,为None     
        a = yield r           
        yield a               
             
                              
if __name__ == '__main__':    
    test = sendTest()         
    print(test.__next__())    
    print(test.send('空条承太郎'))    
    print(test.__next__())    
    print(test.__next__())    
  

# 输出结果
	>>> hello world
	>>> 空条承太郎
	>>> None
	>>> None

在使用send()方法往里面传参的时候,如果未先使用next()或__next__方法唤醒生成器,则会报错,报错示范如下:

def sendTest():               
               
    while True:               
        v = yield 'hello world
        r = yield v      
        a = yield r           
        yield a               
             
                              
if __name__ == '__main__':    
    test = sendTest()         
    print(test.send('空条承太郎'))    
    print(test.__next__())    
    print(test.__next__())  

# 输出结果
    >>> TypeError: can't send non-None value to a just-started generator
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值