概述
生成器:含有yield的函数。(无需借助类就能实现)
功能:函数执行过程中可中断、可重开、可暂停、可续传
为什么要用生成器? 解决内存占用问题,看最后一段代码。
原理:是基于迭代器来实现(既然生成器是一个迭代器,它可以被用在for 循环中),内部会自动创建__iter__()和__next__()方法。
运行规则:
遇到yield,程序暂停,并返回值,下次还从该位置运行
对比return则是程序停止,并返回值
基本语法:
def myGen():
print('生成器执行')
yield 1
yield 2
使用方法1:
>>> my = myGen()
>>> next(my)
生成器执行
1
>>> next(my)
2
>>> next(my)
错误:StopIteration
使用方法2:
通过迭代器可知,for循环可以捕获StopIteration,并结束
>>> for i in myGen():
print(i)
生成器执行
1
2
生成器推导式:
e = (i for i in range(5))
# e 也是一个生成器
next(e)
0
next(e)
1
for each in e:
print(each)
2
3
4
生成器的另一种结构:
def foo():
while True:
res = yield 4
print("res:",res)
g = foo() # 得到了生成器
print(next(g)) # 开始运行生成器g,第一次返回值为4,此时生成器停止
print(next(g)) # 第二次运行:由于4被返回。所以并没有赋值给res,res为None,返回4
# 运行结果
4
res: None
4
代码解析:
g = foo() :
g得到了生成器
print(next(g)) :
开始运行生成器g,第一次返回值为4,此时生成器停止
print(next(g)) :
第二次运行:由于4被返回。所以并没有赋值给res,res为None,返回4
注意:和一般的赋值语句不同,res的值并不是通过yield后面的值赋值的吼
(因为后面的值被返回了,怎么赋?怎么赋?没法赋!没法赋!)
那么res的值时谁赋予的呢?
我们再来看一个小栗子:
def foo():
while True:
res = yield 4
print("res:",res)
g = foo() # 得到了生成器
print(next(g)) # 开始运行生成器g,第一次返回值为4,此时生成器停止
# 以上:和之前一样
print(g.send(7)) # 生成器g 的send()方法,从外部把7送到了生成器内部,赋值给了res
# 运行结果
4
res: 7
4
代码解析:
print(g.send(7)) :
生成器g的send()方法: 从外部把7送到了生成器内部,赋值给了res
由此可见:res的值是通过send()方法,从外部传递的
调用send()与使用next()有点像,都会使生成器进行下一次运行。不同的是send()可以往里传入一个值给res
小栗子:
10 以内的素数之和是:2 + 3 + 5 + 7 = 17
那么请编写程序,计算 2000000 以内的素数之和
如果先把所有的素数找到存在列表里,再累加求和,则占用太大内存可能溢出
用生成器:一次找到一个素数,找一个加一个,不占用内存
import math
# 判断是否为素数
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# 生成器函数
def get_primes(number):
while number:
if is_prime(number):
yield number
number -= 1
a = 0
for each in get_primes(2000000):
a += each
# 每次产生一个值累加
print(a)
# 142913828922
如果你感觉对你有帮助,你的赞赏是对我最大的支持!
最后
以上就是陶醉皮带为你收集整理的python-生成器(通俗详解)的全部内容,希望文章能够帮你解决python-生成器(通俗详解)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复