Python之生成器(yield)


这里是一段防爬虫文本,请读者忽略。
本文原创首发于CSDN,作者IDYS
博客首页:https://blog.csdn.net/weixin_41633902/
本文链接:https://blog.csdn.net/weixin_41633902/article/details/107807691
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!


生成器

00. 概述

  • 生成器generator
    • 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象
  • 生成器函数
    • 函数体中包含yield语句的函数,返回生成器对象
    • 生成器对象,是一个可迭代对象,是一个迭代器
    • 生成器对象,是延迟计算、惰性求值

迭代器一定是可迭代对象,可迭代对象不一定是迭代器


01. 生成器对象举例

  • 代码演示1

def inc():
    for i in range(5):
        yield i


print(type(inc))
print(type(inc()))
x = inc()
print(type(x))
print(next(x))
for m in x:
    print(m, end="* ")
for m in x:
    print(m, "**")

  • 运行结果
<class 'function'>
<class 'generator'>
<class 'generator'>
0
1* 2* 3* 4* 

  • 代码演示2
my_func = (i for i in range(10))
print(type(my_func))
print(next(my_func))
print(next(my_func))
  • 运行结果
<class 'generator'>
0
1
  • 普通的函数调用fn(),函数会立即执行完毕,但是生成器函数可以使用next函数多次执行
  • 生成器函数等价于生成器表达式,只不过生成器函数可以更加的复杂

  • 代码演示3
def gen():
    print("1")
    yield 1
    print("2")
    yield 2
    print("3")
    return 3


print(next(gen()))
print(next(gen()))
g = gen()
print("***********************************")
print(next(g))
print(next(g))
# print(next(g))   # 会报StopIteration 错误
print(next(g, "end"))
  • 运行结果
1
1
1
1
***********************************
1
1
2
2
3
end

  • 在生成器函数中,使用多个yield语句,执行一次后会暂停执行,把yield表达式的值返回
  • 再次执行会执行到下一个yield语句
  • return语句依然可以终止函数运行,但return语句的返回值不能被获取到
  • return会导致无法继续获取下一个值,抛出StopIteration异常
  • 如果函数没有显示的return语句,如果生成器函数执行到结尾,一样会抛出StopIteration异常

02. 生成器

  • 生成器函数
    • 包含yield语句的生成器函数生成 生成器对象的时候,生成器函数的函数体不会立即执行
    • next(generator)会从函数的当前位置向后执行到之后碰到的第一个yield语句,会弹出值,并且暂停函数执行
    • 再次调用next函数,和上一次一样的处理过程
    • 没有多余的yield语句能被执行,继续调用next函数,会抛出StopIteration

  • 演示1

def fn():
    i = 0
    while True:
        i = i + 1
        yield i

def inc(c):
    return next(c)

def inc_two():
    c = fn()
    return next(c)


c = fn()
print(inc(c))
print(inc(c))
print(inc_two())  # 显示1
print(inc_two())  # 显示1
print(inc_two())  # 显示1

  • 运行结果
1
2
1
1
1
  • lambda 表达式是匿名函数
  • return返回的是一个匿名函数

03. 生成器应用:处理斐波那契数

  • 演示代码

def fib():
    x = 0
    y = 1
    while True:
        yield y
        y, x = x+y, y


foo = fib()
for _ in range(10):
    print(next(foo), end=" ")


  • 运行结果
1 1 2 3 5 8 13 21 34 55 

04. 生成器应用

  • 协程coroutine
    • 生成器的高级用法
    • 比进程、线程轻量级
    • 是在用户空间调度函数的一种实现
    • Python3asyncio就是协程实现,已经加入到标准库
    • Python3.5使用asyncawait关键字直接原生支持协程
    • 协程调度器实现思路
      • 2个生成器AB
      • next(A)后,A执行到了yield语句暂停,然后去执行next(B)B执行到yield语句也暂停,然后再次调用next(A),再调用next(B),再周而复始,就实现了调度的效果
      • 可以引入调度的策略来实现切换的方式
    • 协程是一种非抢占式调度

05. yield from

  • 演示代码

def inc():
    for x in range(1000):
        yield x


def inc_two():
    yield from range(1000)

foo = inc()
foo1 = inc_two()
print(next(foo))
print(next(foo))
print(next(foo))
print("***************************")
print(next(foo1))
print(next(foo1))
print(next(foo1))

  • 运行结果
0
1
2
***************************
0
1
2

  • yield fromPython 3.3出现的新语法

    • yield from iterablefor item in iterable:yield item形式的语法糖
    • 从可迭代对象中一个个拿元素
  • 演示代码


def counter(n):
    for x in range(n):
        yield x


def inc(n):
    yield from counter(n)


foo1 = inc(10)
print(next(foo1))
print(next(foo1))
print(next(foo1))
print(next(foo1))

  • 运行结果
0
1
2
3

写在最后的话:

  • 无论每个知识点的难易程度如何,我都会尽力将它描绘得足够细致
  • 欢迎关注我的CSDN博客,IDYS’BLOG
  • 持续更新内容
    linux基础 | 数据通信(路由交换,WLAN) | Python基础 | 云计算
  • 如果你有什么疑问,或者是难题。欢迎评论或者私信我。你若留言,我必回复!
  • 虽然我现在还很渺小,但我会做好每一篇内容。谢谢关注!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值