Python高级篇(08):生成器

一、生成器定义和作用

  1. 定义:Python中,一边循环一边计算的机制,生成器对象也是迭代器对象,支持for循环、next()方法…等。
  2. 作用:循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间
  3. 意义:有一系列数要生成,如果能用生成器实现,可以提高效率

二、生成器创建方法

1、简单生成器:将列表推导式的[ ]改为()

# 列表生成式
_list = [i for i in range(10)]
print(type(_list))  # <class 'list'>
print(_list)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 生成器
_generator = (i for i in range(10))
print(type(_generator))  # <class 'generator'>
print(_generator)  # <generator object <genexpr> at 0x7fbcd92c9ba0>
# 生成器对象取值
print(f"第一次迭代数据是:{_generator.__next__()}")  # 第一次迭代数据是:0
print(f"第二次迭代数据是:{next(_generator)}")  # 第二次迭代数据是:1
# 注意从第三个元素开始了!
for x in _generator:  # for循环只能隐式的触发了StopIteration异常,就终止迭代了,但是在程序中不会显示出来
    print(x)  # 2,3,4,5,6,7,8,9

2、函数对象生成器:使用yield关键字,函数就变成了一个generator

  • yield和return语句使用方法类似,但是普通函数运行到return语句则直接返回代码不再执行;而生成器对象会运行到yield后返回,再下次调用next(),会从yield语句后继续执行。
def gen_generator():
    yield "start"
    for i in range(2):
        yield i
    yield "end"


gen = gen_generator()
print(f"从gen对象取到的第一个值为:{next(gen)}")  # 从gen对象取到的第一个值为:start
print(f"从gen对象取到的第二个值为:{next(gen)}")  # 从gen对象取到的第二个值为:0
print(f"从gen对象取到的第三个值为:{next(gen)}")  # 从gen对象取到的第三个值为:1
print(f"从gen对象取到的第四个值为:{next(gen)}")  # 从gen对象取到的第四个值为:end
# print(f"从gen对象取到的第五个值为:{next(gen)}")  # 抛出StopIteration异常


# 等同于
gen2 = (i for i in ["start", 0, 1, "end"])
for v in gen2:
    print(v)

 三、yield生成器高级应用

send()概念:暂时保留先不进行,等待需要时再进行。作用与next()作用相似。

send()使用:传递值给yield返回(可以指定yield想返回啥就返回啥),如果传None,则等同于next(generator)。

  • send()和next()区别:
    • send(value)可以值传递给yield。
    • next()不能传递特定的值,只能传递generator进去。

使用send():

def genterator_test():
    while True:
        print("--1-")
        num = yield 100  # 需要send传递值才能有num
        print("--2--", "num=", num)


g = genterator_test()

# 等同于next(generator)
print(g.send(None)) # --1-
                    # 100

# 给上一次挂起的yield设置返回值
print(g.send(11))   # --2-- num= 11
                    # --1-
                    # 100

# 给上一次挂起的yield设置返回值
print(g.send(22))   # --2-- num= 22
                    # --1-
                    # 100
  • 第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,可以看到,can't send non-None value to a just-started generator因为生成器just-started generator,是没有Python yield语句来接收这个值的。 

使用next():

def genterator_test():
    while True:
        print("--1-")
        num = yield 100  # 需要send传递值才能有num
        print("--2--", "num=", num)


g = genterator_test()


print(next(g))  # 第一次调用next,跑到 yield 100,遇到yield,执行结束。结果是:--1- 100

print(next(g))
"""
第二次调用next,继续从上一次状态继续执行,此时,需要注意,
我们执行的起点是:num = yield 100,并且这个num值并不是100,而是通过send()传递过来的值,
即:n = send(),但是我们没有调用send()方法,所以,num自然而然为None,
所以,此时是执行print(next(g)),结果是:--2-- num= None    --1-    100
"""

四、yield和yield from区别

  • yield 一次只会返回一个元素,即使返回的元素是个可迭代对象,也是一次性返回
  • yield from提供一个数据传输的管道,后面加的生成器函数对象,调用方是通过这个 “包装函数” 来与生成器进行交互的,即“调用方——>委托生成器——>生成器函数”
# yield
def gen_generator2():
    yield [1, 2, 3]

s = gen_generator2()
print(next(s))  # [1, 2, 3]
# print(next(s))  # StopIteration


# yield from
def gen_generator3():
    yield from [1, 2, 3]

s1 = gen_generator3()
print(next(s1))  # 1
print(next(s1))  # 2
print(next(s1))  # 3

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值