yield去实现列表求和
res=g.send(value) 传值的步骤: value先传给yield, 然后yield传给左边等号的变量x.然后运行yield下面的代码直到下次到yield处进行挂起。然后把yield返回值 返回给res
a = [1,3,5,6,9]
# 计算列表的和
def add(x:list):
summ = 0
index = 0
while index < len(x):
summ += x[index]
index += 1
print(summ)
add(a)
#如果用yied去实现呢
def add1():
res = 0
while True:
x = yield
if x is None: #seed传值为None用来结束循环
break
res += x
print(res)
return res
g = add1()
next(g)
for i in a:
g.send(i)
# 获取生成器的值需要捕获 StopIteration异常 e.value作为返回值。
# for循环生成器 会自动捕获StopIteration,不会有生成器的返回值。
try:
next(g)
except StopIteration as e:
print(e.value)
"""
yield from x x可以是range函数 可迭代对象如列表 字符串 元组 字典, 函数等等
yield from x 类似看成 for i in x: yield i i是子生成器StopIteration异常的 return的返回值。
"""
yield from x 委派生成器
yield from x x可以是range函数 可迭代对象如列表 字符串 元组 字典, 函数等等 yield from x 类似看成 for i in x: yield i i是子生成器StopIteration异常的 return的返回值。
def fo():# fo看作为委派生成器
for i in range(5):
yield i
for m in ("a", "b", "c"):
yield m
for x in ("a", "b", "c"): yield x
# 生成器的调用
f = fo()
next(f) # 生成器初始化 这步必须有
print(list(f)) # [1, 2, 3, 4, 'a', 'b', 'c', 'name', 'age', 'hobby']
# 其实fo函数可以简写为
def fo():
yield from range(5)
yield from ("a", "b", "c")
yield from ("a", "b", "c")
f = fo()
next(f) # 生成器初始化 这步必须有
print(list(f)) # [1, 2, 3, 4, 'a', 'b', 'c', 'name', 'age', 'hobby']
yield from 函数 生成器递归调用
# yield的一个递归案例
# 去除对象5所有的元素到一个列表
a = [1,3,4,["啊登","向佳","咸维维"],[[15,19,["香蕉",["西瓜","芒果"]]],8,0]]
def get_a(a,b):
b = b
for i in a:
if isinstance(i,list) and (not isinstance(i,(str, bytes))) : #b"xxx" bytes数据
get_a(i,b)
else:
b.append(i)
return b
print(get_a(a, []))
# 生成器来实现
a = [1,3,4,["啊登","向佳","咸维维"],[[15,19,["香蕉",["西瓜","芒果"]]],8,0],(456,797)]
from collections.abc import Iterable
def get_a(a):
for i in a:
if isinstance(i,Iterable) and (not isinstance(i,(str, bytes))) : #b"xxx" bytes数据
yield from get_a(i) #生成器函数调用自己本身用yield from 函数
else:
yield i
print(tuple(get_a(a)))
#(1, 3, 4, ['啊登', '向佳', '咸维维'], [[15, 19, ['香蕉', ['西瓜', '芒果']]], 8, 0], (456, 797))
"""
yield from x x是一个Iterabel 可迭代对象。 range() list 元组 字典 字符串 都适用。
这里 yield from x 前面没有用一个参数 去接收 子生成器的返回值。
y = yield from x 子生成器StopIteration异常抛出,return的返回值 y来接收。
yield from 另外一个作用就是可以给子生成器 send值,当send None子生成器就跳出循环。
"""
yield from 委派生成器给子生成器传值过程
def foo(list_total:list):
# 委派生成器
while True:
# x 接收fo生成器的StopIteration,即return返回值。然后接着这行委派生成器yield from下面的代码直到下次yield from处
x = yield from fo()
list_total.append(x)
def fo():
# 子生成器
total = 0
while True:
y = yield
if y is None:
return total
total += y
list_total = []
g = foo(list_total )
next(g) # 初始化,准备给子生成器fo传值.这是后代码会运行到fo函数的yield处
# 循环传值
for i in range(5,9):
g.send(i)
g.send(None) # foo委派生成器 x会接收 fo子生成器return 的返回值total会运行yield from下面的代码 再次进去fo的yield出等待传值
for i in range(20,25):
g.send(i)
g.send(None) # foo委派生成器 x会接收 fo子生成器return 的返回值total会运行yield from下面的代码 再次进去fo的yield出等待传值
print(list_total) # [26, 110]
子生成器的基本框架
while True:
x = yield # 委派生成器给ta传值
if x is None: # 传值为None 终止子生成器
break
.......
......
委派生成器框架
def foo():
while True:
res = yield from fo()
................
使用yeild from写一个异步爬虫
import requests
from collections import namedtuple ①
Response = namedtuple("rs", 'url status') ②
# 子生产器
def fecth(): ③
res=[]
while 1:
url = yield ④
if url is None: ⑤
break
req = requests.get(url)
res.append(Response(url=url, status=req.status_code))
return res
#委派生成器
def url_list(l, key):
while 1: ⑥
l[key] = yield from fecth() ⑦
#调用方
def main():
l = {}
u = ["http://www.baidu.com", "http://www.cnblogs.com"]
for index, url in enumerate(u):
if index == 0:
ul = url_list(l, index)
next(ul) ⑧
ul.send(url)⑨
ul.send(None)⑩
return l
if __name__ == '__main__':
res = main()
print(res)
接下来对上面的标准进行解释:
① 引入一个具名元组,可以后面实现一个简单的类。
② 对请求参数做一个格式化处理,后面通过获取属性即可。
③一个协程,通过requests模块可以发起网络请求。
④main函数的发送的值绑定到这里的url上
⑤ url为None即没有url的时候结束循环的。
⑥这个循环每次都会新建一个fetch 实例,每个实例都是作为协程使用的生成器对象。
⑦ url_list发送的每个值都会经由yield from 处理,然后传给fetch 实例。url_list会在yield from表达式处暂停,等待fetch实例处理客户端发来的值。fetch实例运行完毕后,返回的值绑定到l[key] 上。while 循环会不断创建fetch实例,处理更多的值。
⑧激活url_list生成器
⑨把各个url以及其序列号index,传给url_list传入的值最终到达fetch函数中,url_list并不知道传入的是什么,同时url_list实例在yield from处暂停。直到fetch的一个实例处理完才进行赋值。
⑩关键的一步,ul把None传入url_list,传入的值最终到达fetch函数中,导致当前实例终止。然后继续创建下一个实例。如果没有ul.send(None),那么fetch子生成器永远不会终止,因为ul.send()发送的值实际是在fetch实例中进行,委派生成器也永远不会在此激活,也就不会为l[key]赋值
网友评论