• 020.Python生成器和生成器函数



    一 生成器

    1.1 基本概念

    元组推导式是是生成器(generator) 

    生成器定义

    • 生成器可以实现自定义,迭代器是系统内置的,不能够更改
    • 生成器的本质就是迭代器,只不过可以自定义.

    生成器有两种定义的方式:

    1. 生成器表达式 (里面是推导式,外面用圆括号)
    2. 生成器函数

    1.2  元组推导式的形式来写生成器 

    gen = (i * 2 for i in range(5))
    print(gen)
    from collections import Iterator
    print(isinstance(gen,Iterator))

    执行

    [root@node10 python]# python3 test.py
    <generator object <genexpr> at 0x7fb5ec2e6200>
    True

    1.3 使用for调用生成器

    复制代码
    gen = (i * 2 for i in range(5))
    print(gen)
    from collections import Iterator
    print(isinstance(gen,Iterator))
    for i in gen:
            print (i)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    <generator object <genexpr> at 0x7fd817c1f200>
    True
    0
    2
    4
    6
    8
    复制代码

    1.4 用next进行调用生成器

    复制代码
    gen = (i * 2 for i in range(5))
    print(gen)
    from collections import Iterator
    print(isinstance(gen,Iterator))
    for i in gen:
            print (i)
    gen = (i * 2 for i in range(5))
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    <generator object <genexpr> at 0x7f0b564d0200>
    True
    0
    2
    4
    6
    8
    0
    2
    4
    6
    8
    复制代码

    越界错误

    复制代码
    gen = (i * 2 for i in range(5))
    print(gen)
    from collections import Iterator
    print(isinstance(gen,Iterator))
    for i in gen:
            print (i)
    gen = (i * 2 for i in range(5))
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    res  = next(gen)
    print(res)
    #在添加一个会出现越界错误
    res  = next(gen)
    print(res)
    复制代码

    执行

    1.5 利用for 和next 配合使用 调用生成器

    复制代码
    gen = (i * 2 for i in range(5))
    print(gen)
    from collections import Iterator
    print(isinstance(gen,Iterator))
    gen = (i * 2 for i in range(5))
    for i  in  range(3):
            res = next(gen)
            print(res)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    <generator object <genexpr> at 0x7f5e78ef1200>
    True
    0
    2
    4
    复制代码

    二 生成器函数

    2.1 yield  生成器函数

    yield 类似于 return
    共同点在于:执行到这句话都会把值返回出去
    不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
               而return直接终止函数,每次重头调用.
    yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

    定义一个生成器

    复制代码
    def func():
            print("one")
            yield  1
    
            print("two")
            yield 2
    
            print("three")
            yield 3
    
    # 初始化生成器函数 => 返回一个生成器对象 简称生成器
    gen = func()
    
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    one
    1
    two
    2
    three
    3
    复制代码

    执行过程

    复制代码
    首先初始化生成器函数 返回生成器对象,简称生成器
        有了生成器之后 可以使用next进行依次的调用
        第一次 print(one)   记录当前的状态,暂停等待下一次调用 通过yield 1 返回1 ,阻塞代码
        第二次 print(two)   记录当前的状态,暂停等待下一次调用 通过yield 2 返回2 ,阻塞代码
        第三次 print(three) 记录当前的状态,暂停等待下一次调用 通过yield 3 返回3 ,阻塞代码
        到此已经没有值可以在拿出来了,如果在调用,直接越界报错.
    复制代码

    优化生成器

    复制代码
    def func():
            for i in range(1,101):
                    yield "我的球衣号码是%d" % (i)
    
    # 初始化生成器函数 => 返回一个生成器对象
    gen = func()
    
    for i  in  range(30):
            res = next(gen)
            print(res)
    
    for i in range(50):
            res = next(gen)
            print(res)
    复制代码

    2.2 send生成器函数

    把值发送给上一个yield 进行接收

    next和send区别:

    1. next 只能取值
    2. send 不但能取值,还能发送值

    send注意点:

    1. 第一个 send 不能给 yield 传值 默认只能写None (语法的硬性要求)
    2. 最后一个yield 接受不到send的发送值
    复制代码
    def func():
            print("start")
            res = yield 1
            print(res)
    
            res = yield 2
            print(res)
    
            res = yield 3
    
            print(res)
            print("end")
    #初始化生成器函数,生成生成器 gen = func() # 生成器.send 第一次发送的时候必须参数是None 硬性语法 res = gen.send(None) #这里相当于res = next(gen) print(res)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    start
    1

    第二次可以自定义要发送的值 

    复制代码
    def func():
            print("start")
            res = yield 1
            print(res)
    
            res = yield 2
            print(res)
    
            res = yield 3
    
    
    
            print(res)
            print("end")
    gen = func()
    # 生成器.send  第一次发送的时候必须参数是None 硬性语法
    res = gen.send(None)
    print(res)
    res = gen.send("111")
    print(res)
    
    res = gen.send("222")
    print(res)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    start
    1
    111
    2
    222
    3
    复制代码

    如果没有yield了 , 就没有返回值给你, 在调用直接报错
    如果就像在最后一次调用的时候执行剩下的没跑完的代码,使用try..except..来进行异常处理

    复制代码
    def func():
            print("start")
            res = yield 1
            print(res)
    
            res = yield 2
            print(res)
    
            res = yield 3
    
            print(res)
            print("end")
    gen = func()
    # 生成器.send  第一次发送的时候必须参数是None 硬性语法
    res = gen.send(None)
    print(res)
    res = gen.send("111")
    print(res)
    
    res = gen.send("222")
    print(res)
    
    res = gen.send("222")
    print(res)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    start
    1
    111
    2
    222
    3
    222
    end
    Traceback (most recent call last):
      File "test.py", line 25, in <module>
        res = gen.send("222")
    StopIteration
    复制代码

    执行过程

    复制代码
    发送的时候 是先发送 ,后接受
    
    #第一次发送的时候必须参数是None 硬性语法
    print(start) 记录当前状态, 把yield 1这个值返回取出 , 暂定阻塞,等待下一次调用.
    # 第二次调用时,可以自定义要发送的值 被yield 1 这一行收走了,res接收到send发送过去的值为111
    那么从这一行继续向下执行
    print(res) 111
    res = yield 2
    把2 返回给res = gen.send(111) 这一行 res 接收到2 print(res)
    
    #第三次调用时,发送自定义值222,被res = yield 2接收到 print(res) => 222
    然后执行res = yield 3 记录当前状态,把yield 3 这个值返回取出, 代码暂停阻塞,等待下一次调用.
    复制代码

    2.3 yield from 函数

    • 将一个可迭代对象变成一个迭代器返回
    复制代码
    def func():
            listvar = [1,2,3,4,4,5]
            # yield listvar
            yield from listvar
    
    # 初始化生成器函数 返回生成器对象 简称生成器
    gen = func()
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    print("<=for=>")
    for i in gen:
            print(i)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    1
    2
    3
    4
    <=for=>
    4
    5
    复制代码
    学习记录,小白一枚
  • 相关阅读:
    Java学习第十五章 之 Map、可变参数、Collections
    Java第十四章 之 List、Set
    Java学习第十三章 之 常用API
    通过shell终端上传下载文件
    javamail邮件发送
    linux防火墙添加例外端口shell脚本
    MySQL批量更新
    MySQL返回列名
    发现一个有意思的东西
    struts2,action方法自动执行两次
  • 原文地址:https://www.cnblogs.com/wangsirde0428/p/14322478.html
Copyright © 2020-2023  润新知