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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2018-10-07 18:40  小王子QAQ  阅读(66)  评论(0)    收藏  举报