1、Python 中提供的 生成器:
本质:我们自己写的能实现迭代器功能的东西,就叫生成器。
1.1生成器函数:
常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果。在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行
1.2.生成器表达式:
类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
2、生成器Generator:
本质:迭代器 ( 所以自带了 __iter__方法和 __next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义
3、生成器函数:
划重点:
① 必须含有yield关键字
② 执行之后会得到一个生成器对象,作为返回值
def generator():
print('123')
yield 'ab'
ret = generator()
print(ret) # <generator object generator at 0x000001DA911EC3B8>
print(ret.__next__()) # 第一次执行函数体内的代码,如上①输出123 ②return ab
def wahaha():
for i in range(2000):
yield '娃哈哈%s'%i
g = wahaha()
count = 0
for i in g: # 循环迭代输出
count += 1
print(i)
if count > 100:
break
print('*********',g.__next__()) #********* 娃哈哈101
4、field关键字
4.1 yield和return的区别
# 在一个函数里return只能执行一次,return之后函数就彻底结束了:
def test_return():
return 1
return 2 # 永不执行
return 3 # 永不执行
def test_return2():
for i in range(10):
return i # 只能返回0,函数就结束了
——————————————————————————————————————
# yield之后可以保存函数的运行状态,下次继续执行:【在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行】
def test_yield():
yield 1
yield 2 # 下次next()后执行
yield 3 # 下次next()后执行
def test_yield2():
for i in range(10):
yield i # 每调用一次next()就会依次弹出0~9
4.2 yield的作用
# ① yield把函数变成了生成器(生成器就是迭代器)。 # ② 为函数封装好了__iter__和__next__方法,把函数的执行结果做成了迭代器。 # ③ 遵循迭代器的取值方式 — obj.__next__(),触发的是函数的执行。函数暂停与继续执行的状态都是由yield保存的。
# 倒计时的例子
def countdown(n):
print("倒计时开始")
while n > 0:
yield n
n -= 1
print("发射")
g = countdown(5)
print(g.__next__()) # 打印"倒计时开始" 返回5 (此时n=5)
print(g.__next__()) # 返回4 (此时n=4)
print(g.__next__()) # 返回3 (此时n=3)
print(g.__next__()) # 返回2 (此时n=2)
print(g.__next__()) # 返回1 (此时n=1)
print(g.__next__()) # 打印"发射" 抛出StopIteration异常(此时n=0)
4.3 yield from:在一个生成器中引用另外一个生成器
yield from后面需要加的是可迭代对象,它可以是普通的可迭代对象,也可以是迭代器,甚至是生成器。
详细查看 https://www.cnblogs.com/wongbingming/p/9085268.html

def generator():
a = '12312312'
b = 'asdhughiwu'
yield from a
yield from b
g = generator()
for i in g:
print(i)
# 运行结果:
1
2
3
1
2
3
1
2
a
s
d
h
u
g
h
i
w
u
astr='ABC' # 字符串
alist=[1,2,3] # 列表
adict={"name":"wangbm","age":18} # 字典
agen=(i for i in range(4,8)) # 生成器
def gen(*args, **kwargs):
for item in args:
yield item # 此处返回的是'ABC',[1,2,3],{"name":"wangbm","age":18},<generator object <genexpr> at 0x000001D0A010C3B8>
yield from item # 相当于 for i in item:yield i
new_list=gen(astr, alist, adict, agen)
print(list(new_list))
# 运行结果:
# ['ABC', 'A', 'B', 'C', [1, 2, 3], 1, 2, 3, {'name': 'wangbm', 'age': 18}, 'name', 'age', <generator object <genexpr> at 0x00000256B8D6C3B8>, 4, 5, 6, 7]
5、send关键字
yield可以返回值,也可以接收值。
通过生成器的send方法可以给yield传值。
# 必须先执行__next__,才能执行send()
# send两个作用:
# 1.给yield传值
# 2.继续执行函数
def eat(name):
print('%s要开始吃了!' % name)
while 1:
food = yield
print('{0}在吃{1}'.format(name, food))
a = eat('alex')
a.__next__() # 初始化,让函数暂停在yield处
a.send('包子')
a.send('饺子')
6、生成器表达式
详见:https://www.cnblogs.com/timetellu/p/10677743.html
把列表解析的[ ]换成( )得到的就是生成器表达式:
sum(x ** 2 for x in range(4)) # 不用多此一举构造一个列表 # sum([x ** 2 for x in range(4)])

7、生成器相关面试题

# 只能取一次值
def demo():
for i in range(10):
yield i
g = demo()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list(g2)) # [ ]

def add(n,i):
return n+i
def test():
for i in range(4): # [0,1,2,3]
yield i
g = test()
for n in [1,10]:
g = (add(n,i) for i in g)
print(list(g)) #到list(g)才执行,向上寻找g,取得是for循环最后一步的执行结果:
# 执行g = (add(n,i) for i in (add(n,i) for i in test())) (此时n=10)
运行结果:
[20, 21, 22, 23]
### for循环套生成器表达式的,执行过程拆开
# n = 1时,
# g0 = (add(n,i) for i in g)
# n = 10时,
# g1 = (add(n,i) for i in g0)
# g = (add(n,i) for i in (add(n,i) for i in test())) 此时n = 10
# g = (add(10,i) for i in (10,11,12,13))
来源:https://www.cnblogs.com/timetellu/p/10681281.html
