传送门
无字天书之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
,yield
和return
非常相似,都可以返回值,但是不同的式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
条件设置的是永真,所以这个循环实不会停下来的。
这里我们定义了两个生成器,并且在一个循环中调用两个生成器,这样看起来就是两个任务同时在执行。