一 生成器
生成器的本质就是迭代器
1 生成器的特点和迭代器一样 取值方式和迭代器一样(_next_(),send():给上一个yield传值
2 生成器一般由生成器函数或者生成器表达式来创建
3 其实就是手写的生成器
4 在pytion中有三种方式来获取生成器
通过生成器函数
通过各种推导式来实现生成器
通过数据的转换也可以获取生成器
特点:
1 惰性机制
2只能向前
3节省内存
list中拿数据是全部一起拿,不是一个一个拿,里面有__next__ for 循环中也有__next__
列如:
def func(): print("111") return 222 return返回一个值 ret =func() print(ret)
结果:
111
222
将函数中的return换成yield就是生成器
1 def func(): 2 print("111") 3 yield 222 yield 就是一个生成器函数 4 ret =func() 形成一个生成器 5 print(ret)
结果:
<generator object func at 0X10597ff68>
通过执行_next_()来执行以下生成器
1 def func(): 2 print("111") 3 yield 222 4 genner =func() 这个时候函数不会执行 而是获取生成器 5 ret =genner.__next__() 这个时候函数才能执行 yield的作用和return一样 也是返回数据 6 print(ret) 7 8 9 结果: 10 111 11 222
yield是分段来执行一个函数 而return是直接停止执行函数
1 def func(): 2 print("111") 3 yield 222 4 print("333") 5 yiled 444 6 gener =func() 7 ret =genner._next_() 8 print(ret) 9 ret2=genner._next_() 10 print(ret2) 11 ret3=genner._next_() 最后一个yield执行完毕 再次_next_()程序会报错 12 print(ret3) 13 14 15 结果: 111 Traceback (most recent call last): 222 333 File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in <module> 444 ret3 = gener.__next__() # 最后⼀一个yield执⾏行行完毕. 再次__next__()程序报错, 也 就是说. 和return⽆无关了了. StopIteration 16
1 def func(): 2 print("111") 3 yield 222 4 print("333") 5 yiled 444 6 gener =func() 7 ret =genner._next_() 8 print(ret) 9 ret2=genner._next_() 10 print(ret2) 11 ret3=genner._next_() 最后一个yield执行完毕 再次_next_()程序会报错 12 print(ret3) 13 14 15 结果: 111 Traceback (most recent call last): 222 333 File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in <module> 444 ret3 = gener.__next__() # 最后⼀一个yield执⾏行行完毕. 再次__next__()程序报错, 也 就是说. 和return⽆无关了了. StopIteration 16
当程序运行完最后一个yield 那么后面进行_next_()程序会报错
来个实列
采购10000套学士服 直接造出来10000 一次性给完
def cloth(): lst=[] for i in range(0,10000): lst.append("衣服"+str(i)) return lst c1 =cloth()
我想要一套一套拿衣服 该怎么办呢
1 def cloth(): 2 for i in range(0,10000): 3 yield"衣服"+str(i) 4 cl =cloth() 5 print(cl.__next__()) 6 print(cl.__next__()) 7 print(cl.__next__()) 8 print(cl.__next__()) 一个一个取
区别: 第一种是直接一次性全部拿出来 会很占用内存 第二种使用生成器 一次就一个 用多少生成多少 生成器是一个一个的指向下一个 不会回去 __next__()到哪 指针就指到哪儿 下一次继续获取指针指向的值
接下来看send()方法 send和__next__一样都可以让生成器执行下一个yield send()的()里面必须给定参数
1 def eat(): 2 print("我吃什么啊") 3 a =yield 4 print("a"=,a) 5 b=yield 6 print("b"=,b) 7 c=yield 8 print("c"=,c) 9 yield 10 11 gen=eat() 12 ret1=gen.__next__() 13 print(ret1) 14 ret2=grn.__next__() 15 print(ret2) 16 ret3=gen.__next__() 17 print(ret3) 18 ret4=gen.__next__() 19 print(ret4)
send和__next__()区别:
1 send和next()都是让生成器向下走一次
2send可以给上一次yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send()
生成器可以使用for循环来循环获取内部的元素:
def func(): print(111) yield 222 print(333) yield 444 print(555) yield 666 gen=func() for i in gen(): print(i) 结果: 111 222 333 444 555 666
二 列表推导式,生成器表达式以及其他推导式
lst =[] for i in range(1,15): lst.append(i) print(lst)
替换成列表推导式
lst=[i for i in range(1,15)] print(lst)
例如: 从Pythion1期到pytion14期写入列表lst:
lst=['pytion%s' % i for i in range(1,15)] print(lst)
我们还可以对列表中的数据进行筛选
筛选模式:
[结果 for 变量 in 可迭代对象 if 条件]
获取1-100内所有的偶数 lst =[i for i in range(1,100) if i %2==0] print(lst)
生成器表达式和列表推导式的语法基本上是一样的 只是把[]替换成()
gen =(i for i in range(10)) print(gen)
结果:
<generator object <genexpr> at 0x106768f10>
打印的结果就是一个生成器,我们可以使用for循环来循环这个生成器
gen=("马化腾我第%s次爱你" % i for i in range(10)) for i in gen: print(i)
二生成器函数
和普通函数没有区别 里面的yield的函数就是生成器函数
生成器函数在执行的时候 默认不会执行函数体 返回生成器
通过生成器的_next_()分段执行这个函数
send()给上一个yield传值 不能在开头(没有上一个yield),最后一个yield也不能用send()
三 推导式
1 列表推导式[结果 for循环 条件筛选]
2字典推导式[k,v for循环 条件筛选}
把字典中的key和value互换 dic ={'a':1,'b':2} new_dic={dic[key]:key for key in dic} print(new_dic) #在以下list中 从lst1中获取到的数据和lst2中相对应的位置的数据组成一个新字典 lst1 = ['jay', 'jj', 'sylar'] lst2 = ['周杰伦', '林林俊杰', '邱彦涛'] dic ={lst1[i]:lst2[i] for i in range(len(lst1))} print(dic)
3集合推导式{k for循环 条件}
集合的特点:无序,不重复 所以集合推导式自带去重的功能 lst=[1,-1,8,-8,12] s ={abs(i) for i in lst} print(s)
总结:推导式有列表推导式,字典推导式,集合推导式,没有元组推导式
四 生成器表达式 (拿到的是一个生成器,只有执行__next__才能取值)
(结果 for循环 条件)
gen =(i for i in range(1,100) if i%3 ==0) for num in gen: print(num)
100以内能被3整除的数的平方 gen =(i *i for i in range(100) if i%3==0) for num in gen: print(num)
寻找名字中带两个e的人的名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 不用推导式和表达式 result=[] for i in names: for name in i: if name.count("e") >=2: result.append(name) print(result)
推导式 gen=(name for first in names for name in first if name.count("e") >=2) for name in gen: print(name)
生成器表达式和列表推导式的区别:
1 列表推导式比较耗内存 一次性加载 生成器表达式几乎不占内存 使用的时候才分配和使用内存
2 得到的值不一样 列表推导式得到的是一个列表,生成器表达式获取的是一个生成器
生成器的惰性机制:生成器只有在访问的时候才取值
def func(): print(111) yield 222 g=func() 生成器g g1=(i for i in g) 生成器g1,但是g1的数据来源于g g2=(i for i in g1) 生成器g2 来源于g1 print(list(g)) 获取g中的数据 这时func()才会被执行 打印111 获取到222 g完毕 print(list(g1)) 获取g1中的数据 g1的数据来源是g 但是g 已经取完了 g1也没有数据 print(list(g2)) 和g1 同理
def add(a,b): retern a+b def test(): for r_i in range(4): yield r_i g=test() for n in [2,10]: g=(add(n,i) for i in g) print(list(g)) 惰性机制,不到最后不会拿值