12.生成器和推导式
生成器
生成器:本质是迭代器,写法和迭代器不一样,用法和迭代器一样
生成器函数:函数中带有Yield,执行生成器函数的时候返回生成器,而不是执行这个函数
在python中有三种方式获取生成器:
1.通过生成器函数
2.通过各种推导式来实现生成器
3.通过数据转换也可以获取生成器
def func(): print ('你好啊,大帅比') return '对,你就是大帅比' ret = func() print (ret) 普通函数
yield
def func(): print ('你好啊,大帅比') yield '对,你就是大帅比' #return 和 yield 都可以返回数据 ret = func() # 以前的函数名() 直接开始执行 yield情况下反悔的是 generator ret是一个生成器 print (ret) s = ret.__next__() #当执行到__next__()函数才真正的开始执行 print('接收到的是',s) 只要有yield 函数不执行,返回的是生成器,执行__next__()
关于生成器简单函数
lst = [] def func(): for i in range(10000): lst.append('衣服%s'%i) return lst lst = func() print (lst) def func(): for i in range(10000): yield '衣服%s'%i gen = func() #gen就相当于订单 func一执行拿到的是生成器 在这里不能使用yf1 = func().next 这样相当于每次都拿到一个生成器 从一个生成器里向下执行__next__() yf1 = gen.__next__() print (yf1)
由于函数中存在了yield 那么这个函数就是一个生成器函数,这个时候,我们再执行函数的时候,就不是函数的执行,而是获取这个生成器
通过函数可以了解到,yield和return的效果是一样的区别是
yield是分段来执行一个函数,return是直接停止执行函数
当程序运行完最后一个yield,那么后面继续执行__next__()会报错
send和__next__()的区别
def func(): print ('刘德华') a = yield '老男神' print('周杰伦',a) b = yield '周天王' print ('梁朝伟',b) yield'林志玲' x = func() ret = x.__next__() print(ret) ret = x.send('山炮') print (ret) ret = x.send('彪货') print(ret) 首先执行func()是生成一个生成器 send 和 __next__()的区别 1.send不可以用在开头 2.send可以给上一个yield传值,不可以给最后一个yield传值
生成器可以使用for循环来获取内部元素
def func(): yield'刘强东' yield'马云' yield'马化腾' yield'腾讯' yield'支付宝' x = func() print (x.__next__()) print (x.__next__()) print (x.__next__()) print (x.__next__()) print (x.__next__()) 生成器的第一种操作,生成器的本质就是迭代器 print('__iter__'in dir(x)) for i in x: print(i) 有__iter__()表示可以迭代,可以使用for循环 第二种操作 生成器可以直接使用for循环 lst = list(x) print (lst) 把生成器中的每一个数据拿出来组合成列表
二 列表推导式,生成器表达式及其它推导式
像列表中添加1-14
lst = [] 创建新列表 for i in range(1,17): 循环1-16 lst.append('python%s期'%i) 装数据 print (lst) 推导式 列表推导式 [结果 for循环 if筛选 ] lst = ['python%s'%i for i in range(1,17) ] print (lst) 列表推导式是通过一行代码来实现的,看起来简单,但是遇到错误很难排查
几个列表推导式的简单操作
创建列表 [1,3,5,7,9....99] lst = [i for i in range(1,100) if i%2 ] print (lst) 创建1-100能被3整除得数 lst = [i for i in range(1,100) if i%3==0 ] print (lst) 创建1-100能被3整除得数的平方 lst = [i*i for i in range(1,100) if i%3==0 ] print (lst) names = [['jack','defew','grreg','hytyhgf','yjjj','ytj','tyjt','rtrt','ererrt'],['thfgfdfd','rgre','grg','Tom','gergef','gerge','regeg','ergreg']] # 寻找名字中带有两个e的名字 lst = [name for first in names for name in first if name.count('e')>= 2] first代表第一层, 再对first进行循环 print (lst) 推导式适合比较简单的,循环套的比较多,不容易看懂,不建议使用
字典推导式
1 {key:value for循环 if筛选} 2 dic = {'张无忌':'九阳神功','周芷如':'九阴真经','乔峰':'降龙十八掌','灭绝师太':'倚天剑'} 3 d = {dic[k]:k for k in dic} 4 print (d) 5 6 lst1 =['东北','陕西','山西','开封','杭州','广东','济南'] 7 lst2 = ['大拉皮','油泼面','老陈醋','灌汤包','红烧鲤鱼','早茶','大虾'] 8 9 dic = {lst1[i]:lst2[i] for i in range(len(lst1))} 10 print (dic)
集合推导式
{key for if} 集合的特点 无序,不重复 可哈西
lst1 =['东北','陕西','山西','开封','杭州','广东','济南','杭州','杭州','杭州']
s = {i for i in lst1}
print (s) #去重功能
生成器表达式和列表表达式的语法基本上是一样的只是把[ ]替换成()
x = (i for i in range(100) )
print (x) 类似于元组的推导式,但其实拿到的是生成器
打印的结果是
<generator object <genexpr> at 0x00000237AC149390>
是生成器表达式
生成器表达式 记录下代码,每次需要的时候去生成器中执行一次代码
列表表达式 一次性把所有的数据创建出来 容易产生内存的浪费
生成器表达式的特性是1.节省内存2.惰性机制3.只能向前
生成器的惰性机制:生成器只有在访问的时候才会执行取值,说白了你找它要,
他才给你值,不要,他是不会执行的
几个重要的典型习题(面试题)
def func(): print (111) yield(222) g = func() 此刻是生成一个生成器,不执行函数 g1 = (i for i in g) 生成器g1但是g1的数据来源于g g2 = (i for i in g1) 生成器g2 来源于g1 print (list(g))获取g中的数据,这是func才会被执行 打印111 获取222 print (list(g1))获取g1的数据,g1的数据来源是g 但是g已经取完了,g1也就没有数据了 print (list(g2))和g1同理
def add(a,b):
return a + b
def test():
for i in range(4):
yield i
g = test()
for n in [2,10]
g = (add(n,i)for i in g)
print (list(g))
for 循环可以等效为
n =2
g = (add(n,i)for i in range(4))
n =10
g = (add(n,i)for i in (add(n,i)for i in range(4)) )
并不执行n =2 的过程,但操作表达式要执行所以只跑n = 10
浙公网安备 33010602011771号