python中的迭代对象,迭代器,生成器
1.python中迭代对象
2.Python中迭代器
3.python的函数的执行图
在执行上述代码时,python解释器(python.exe)会用一个叫PyEval_EvalFrameEx()(C函数)会执行funct1函数,首先会创建栈帧(stack_frame上下文)当func1调用子函数func2又会创建一个栈帧,(看成一对象),所有的栈帧都是分配在堆内存上(堆内存特点:只要不释放,一直存在堆内存中)这就决定了栈帧可以独立于调用者
4.python中的生成器
1.概念:
生成器函数,函数中只要有yield关键字
2.产生:
生成器对象,在python编译字节码的时候产生
3.原理:
生成器函数在普通函数中Heap memery进行了进一步的封装,具体看下图
def gen_func():
yield 3
name = "body"
yield 5
age = 25
return "gen_func"
gen = gen_func()
print(dis.dis(gen))
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
输出:
20 0 LOAD_CONST 1 (3)
2 YIELD_VALUE
4 POP_TOP
21 6 LOAD_CONST 2 ('body')
8 STORE_FAST 0 (name)
22 10 LOAD_CONST 3 (5)
12 YIELD_VALUE
14 POP_TOP
23 16 LOAD_CONST 4 (25)
18 STORE_FAST 1 (age)
24 20 LOAD_CONST 5 ('gen_func')
22 RETURN_VALUE
None
-1
{}
2
{}
12
{'name': 'body'}
3.python中的生成器(进阶)
生成器的三个方法:
1.send()
代码块:
def gen_func():
html = yield "http://www.xxxxxx.com"
print(html)
yield 3
yield 4
return "csdn"
if __name__ == "__main__":
gen = gen_func()
"""
#在此处调用send发送非None值前,必须启动一下生成器
调用的方法有两种:
1.gen.send(None)
2.next(gen)
"""
url = gen.send(None)
print(url)
number = gen.send("cccc")
print(number)
输出:
http://www.xxxxxx.com
cccc
3
总结:
send方法的作用:
可以传递值进入生成器内部,同时还可以启动生成器执行下一个yield
1.close()
代码块:
def gen_func():
yield 2 #代码1的位置
yield 3 #代码2的位置
return "csdn"
if __name__ == "__main__":
gen = gen_func()
print(next(gen))
gen.close()
"""
注释:
当执行close()方法时,会在代码1的位置抛出一个GeneratorExit的异常,所以当在close()后在执行next(gen)方法时程序会报错,错误类型为GeneratorExit
GeneratorExit的异常时继承BaseException的
"""
3.throw()
代码块:
def gen_func():
try:
yield 1 #代码1位置
except Exception as e:
print(e)
yield 2 #代码2位置
yield 3 #代码3位置
return "csdn"
if __name__ == "__main__":
gen = gen_func()
print(next(gen))
a = gen.throw(Exception, "error")
print(a)
print(next(gen))
输出:
1
error
2
3
"""
由输出结果可以看出throw()方法可以在当前代码位置抛出异常,并重启生成器执行下一个yield
"""
4.python中的生成器之间 >>>>>>> yield from
代码块:
def g1(gen):
yield from gen
def main():
g = g1(gen)
g.send(None)
"""
概念:
1.main为调用方
2.g1是委托生成器
3.gen子生成器
作用:
yield from会在调用发方和子生成器间建立一个双向通道
"""
yield from 在调用方和子生成器建立双向通道的例子如下:
final_result = {}
def sales_sum(pro_name):
total = 0
nums = []
while True:
x = yield #表示只接收send来值
print(pro_name + "销量:", x)
if not x:
break
total += x
nums.append(x)
return total, nums
def middle(key):
while True:
final_result[key] = yield from sales_sum(ke
print(key + "完成")
def main():
data_sets = {
"鞋": [1200, 1300, 5000],
"手机": [28, 53, 100, 90],
"裤子": [280, 560, 776, 10]
}
for key, data_set in data_sets.items():
print("start key:", key)
m = middle(key)
m.send(None) # 预激活middle协程
for value in data_set:
m.send(value) # 给协程传递一组数据, 此时发送的value值直接被 sales_sum方法中的x接收
m.send(None)
print("final_result:", final_result)
if __name__ == '__main__':
main()
yield from所处理的逻辑
处理了很多异常的逻辑具体如下:
1.子生成器生产的值,都是直接传给调用方,通过send()发送的值都是直接传递给子生成器的,如果发送的None,会调用子生成器的__next__方法,如果不是None, 会调用子生成器的send()方法
2.子生成器退出的时候,最后return会触发一个StopIteration(EXPR)异常
3.yield from表达式的值,是子生成器终止时传递给StopIteration异常的第一个参数
4.如果调用的时候出现StopIteration异常,委托生成器会恢复运行,同时其他异常会向上"冒泡"
5.传入委托生成器的异常里,除了GeneratorExit之外,其他的所有异常全部传入给子生成器的throw()方法,如果调用throw()的时候出现StopIteration异常,那么就恢复委托生成器的运行,其他异常全部向上"冒泡"
6.如果在委托生成器上调用close()或传入GenerationExit异常,会调用子是生成器的close()方法,没有的话就不会调用,如果在调用close()的时候抛出了异常,那么就向上"冒泡",否则的话委托生成器会抛出GenerationExit异常