无字天书之Python第十三页(生成器基础)

博客目标

传送门

无字天书之Python第一页
无字天书之Python第二页
无字天书之Python第三页
无字天书之Python第四页
无字天书之Python第五页
无字天书之Python第六页
无字天书之Python第七页
无字天书之Python第八页
无字天书之Python第九页
无字天书之Python第十页
无字天书之Python第十一页
无字天书之Python第十二页

正文

注意:列表太大的话会占用过大的内存,可以使用迭代器,只拿需要使用的部分

生成器的设计原则和迭代器是相似的,如果需要一个非常大的集合,不会将元素全部都放到这个集合中,而是将元素保存成生成器的状态,每次迭代的时候返回一个值。
比如我们要生成一个列表,可以采用如下方式:

list1=[x*x for x in range(5)]
print(list1)

结果如下

[0, 1, 4, 9, 16]

如果我们生成的列表非常的巨大,比如:
友情提醒,这么大的列表创建请慎重,如果电脑配置不够很有可能会将电脑卡死。本人16G运行内存即将跑满…

list2 = [x*x for x in range(1000000000000000000000000)]

结果

Traceback (most recent call last):
  File "E:/Python/DataType/thirteen.py", line 6, in <module>
    list2 = [x*x for x in range(1000000000000000000000000)]
  File "E:/Python/DataType/thirteen.py", line 6, in <listcomp>
    list2 = [x*x for x in range(1000000000000000000000000)]
MemoryError

报错了,报错信息提示我们存储异常,并且整个程序运行了相当长一段时间。

如果我们使用生成器就会非常方便了,而且执行速度嗖嗖的
在这里插入图片描述

generator1 = (x*x for x in range(1000000000000000000000000))
print(generator1)
print(type(generator1))

结果:

<generator object <genexpr> at 0x00000180E72AF6D0>
<class 'generator'>

可以看出来数据不知道怎么读取,所以就有了下面的生成器数据读取(和之前的迭代器一样的读取,使用next()函数读取)

generator2=(x*x for x in range(5))
print(next(generator2))
print(next(generator2))
print(next(generator2))
print(next(generator2))
print(next(generator2))
print(next(generator2)) # 这个会报错

结果

0
1
4
9
16
Traceback (most recent call last):
  File "E:/Python/DataType/thirteen.py", line 18, in <module>
    print(next(generator2)) # 这个会报错
StopIteration

一直到最后会抛出异常StopIteration异常,但是很显然,使用这种方法我们是没有办法知道什么时候会迭代结束,所以我们可以使用for循环来获取每个生成器生成的具体的元素,并且for循环同时也无需去关心最后的StopIteration异常

generator3=(x*x for x in range(5))
for index in generator3:
    print(index)

结果:

0
1
4
9
16

本身的generator非常的强大,本质上面,generator并不会获取存储我们的具体元素,它村粗的推算是算法,通过算法获取推算出下一个值
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现

def print_a(max):
    i=0
    while i<max:
        i +=1
        yield i

a=print_a(10)
print(a)
print(type(a))

结果:

<generator object print_a at 0x0000013ED3EEF6D0>
<class 'generator'>

这里使用到了关键字yield,yieldreturn非常相似,都可以返回值,但是不同的式yield不会结束函数

我们调用几次这个用函数创建的生成器:
print(next(a))
print(next(a))
print(next(a))
print(next(a))
结果

1
2
3
4

可以看出来,当我们使用next()对生成器进行一次操作的时候就返回一次循环的,在yield这里结束本次的运行。但是在下一次执行next()的时候,会接着上一次的断点接着运行。直到下一个yield,并且不断的循环往复,直到运行至生成器的最后。
还有一种与next()等价的方式,直接看示例代码:

print(a.__next__())
print(a.__next__())

结果:

5
6

下一个方法就更加牛逼了,不仅能迭代,还能给函数再传递一个值回去:

def print_b(max):
    i = 0
    while i < max:
        i += 1
        args = yield i
        print('传入参数为:'+args)

b = print_b(20)
print(next(b))
print(b.send('only老K,我为自己带盐'))

结果:

1
传入参数为:only老K,我为自己带盐
2

上面BBDD这么多,可能各路神仙还不知道生成器能干什么啊,这里说下一个名字————协程。
再介绍协程之前先介绍下什么式多线程,就是同一个时间内可以执行多个程序,简单理解就是平时可能一边玩手机一边听歌(毫无违和感)
在这里插入图片描述
协调更加贴切的理解就是流水线,比如某件事情必须先做A在做B,并且两个事情看起来是一起做的
结果

执行A
执行B
执行A
执行B
执行A
执行B
执行A
执行B

因为while条件设置的是永真,所以这个循环实不会停下来的。
这里我们定义了两个生成器,并且在一个循环中调用两个生成器,这样看起来就是两个任务同时在执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值