python函数生成器_python函数--生成器

1     生成器

1.1   生成器的背景

迭代器的好处就是节省内存,而在某些情况下,我们也需要节省内存,就只能自己写。而我们自己写的这个实现迭代器功能的东西就是生成器

1.2   生成器的本质、特点

本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码

特点:和迭代器的特点相同;惰性、节省内存、一步步执行

2     生成器函数

一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

生成器函数() -->获取的是生成器. 这个时候不执行函数

def func():

print("111")

yield 222

gener = func()  # 这个时候函数不会执行. 而是获取到⽣成器

ret = gener.__next__()  # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据

2.1   yield和return的区别

yield是分段来执行一个函数. return呢? 直接停止执行函数.

send和__next__()区别:

(1) send和next()都是让生成器向下走一次

(2) send可以给上一个yield的位置传递值, 不能给后一个yield发送值. 在第一次执行生

成器代码的时候不能使用send()

2.2   生成器函数的执行方式获取数据

2.2.1 一个一个获取

2.2.1.1  __next__()

deffunc():print("111")yield 222

print("333")yield 444gener=func()

ret= gener.__next__()print(ret) #222

ret2 = gener.__next__()print(ret2) #333

ret3 = gener.__next__() #最后一个yield执行完毕. 再次__next__()程序报错,

print(ret3)

使用生成器. 一次就一个. 用多少生成多少.  生成器是一个一个的指向下一个.  不会回去, __next__()到哪, 指针就指到哪. 下一次继续获取指针指向的值

---->可以看出特点:一步一步向下执行,节省内存

2.2.1.2  Send()

Send()必须有参数,否则会报错

send() 和__next__()是一样的. 可以执行到下一个yield, 可以给上一个yield位置传值

# def func():

#    print("我是第一个段")

#   a =yield 123

#     print(a)

#   b = yield 456

#     print(b) # ??

#     print("赵一宁是第三段")

#   c = yield 789

#  print(c)

#     print("刘伟是最后一个段")

#     yield 79  # 最后收尾一定是yield

#

# g = func()   #获取生成器

# print(g.__next__()) # 没有上一个yield 所以不能使用send() 开头必须是__next__()

# print(g.send("煎饼果子"))

# print(g.send("韭菜盒子"))

# print(g.send("锅包肉"))  ## ??

2.2.2 一次性获取

List()、set()、str()、tuple()、for循环

3     推导式

3.1   列表、字典、集合推导式

lst =[]for i in range(1,15):

lst.append(i)print(lst)

替换成列表推导式:lst1 = [i fori inrange(1,15)]

print(lst1)

列表推导式是通过一行来构建你要的列表, 列表推导式看起来代码简单. 但是出现错误之

后很难排查.

列表推导式的常用写法:

[ 结果 for 变量 in 可迭代对象

判断条件]

3.2

生成器表达式

生成器表达式和列表推导式的区别:

(1)列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存. 使用的时候才分 配和使用内存

(2)得到的值不一样. 列表推导式得到的是一个列表. 生成器表达式获取的是一个生成器.

生成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成()

gen = (i for i in range(10))print(gen)

结果: at 0x000001EFBA75EDB0>

# 寻找名字中带有两个e的人的名字

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],  ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

# 不用推导式和表达式

result =[]for first innames:for name infirst:if name.count("e") >= 2:

result.append(name)

# 推导式

gen = (name for first in names for name in first if name.count("e") >= 2)for name ingen:print(name)

4     生成器的惰性机制的详细解释

def add(a,b): #加法器

return a +bdef test(): #生成器

for i in range(4):yieldi

g=test() #获取生成器

for n in [1,10]: #这个for循环并未执行生成器,生成器执行的方式:__next__()、send()、list()等

g=(add(n,i) for i in g)#for循环执行完时,n=10,g=(add(n,i) for i in (add(n,i) for i in g))

#--->g=(add(10,i) for i in (add(10,i) for i in g))

print(g.__next__()) #20,此时才执行生成器的一步,指针就指向了这一步后

print(g.__next__()) #21,此时才执行生成器的一步,指针就指向了这一步后

print(list(g)) #[22,23]这一步是在上一步的基础上,把下面所有的步骤全部执行完,到此时生成器执行完

print(list(g)) #[],上面的生成器已经执行完毕,所以为空,list没有__next__()方法,所以没有StopIteration的报错

#结果显示[]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值