Python生成器函数

原文地址

生成器本质上也是一个迭代器,我的一点理解的话,它也有点像只能执行一轮的单链表,通过 obj.__next__()就获得了当前指针(并不是真的指针)的指向值,同时将将指针指向一下个,过程不可逆,最后一个元素执行完之后这个生成器基本上就没法用了。

  • 首先看一个普通函数

    # 一个普通函数
    def generator1():
        print(1)
        return 'a'
    ret = generator1()
    print(ret)
    # 1
    # a
    
  • 一个生成器函数

    def generator2():
        print(1)
        yield 'a'   # 有yield,这是一个生成器函数
    # #生成器函数 : 执行之后会得到一个生成器作为返回值
    ret = generator2()   # 生成器对象
    print(ret)
    # <generator object generator at 0x00000196912B14C8>
    print(ret.__next__())   # 通过.__next__才能取值
    # 1
    # a
    

    通过关键字yield来返回值的函数是一个生成器函数

    yieldreturn不能同时出现在同一个函数中

  • 薛微复杂一点的生成器函数

        print(1)
        yield 'a'
        print(2)
        yield 'b'
        yield 'c'
        # print('最后一个yield之后的操作')	# 在最后一个yield之后不允许在有操作,解决方法见下文
    g = generator3()
    ret = g.__next__()
    print(ret)
    # 1
    # a
    ret = g.__next__()
    print(ret)
    # 2
    # b
    ret = g.__next__()
    print(ret)
    # c
    # print(g.__next__())	# 报错,在最后一个yield之后在进行next操作报错
    
  • 生成器——send方法

    生成器.send()方法的做事是与生成器进行交互,对生成器传值

    在这里还给出了 在最后一个yield之后继续操作的 的方式

    def generator4():
        print(123)
        content = yield 1   # 这个yield返回之后,执行send操作,赋值给content
        print('=======', content)
        print(456)
        arg = yield '这是实际用到的最后一个yield了'
        print('这里是最后一个yield之后的一些操作')
        # 最后一个yield之后不应再有操作,否则报错
        # 可以把最后一个yield写成上面的形式(用一个变量来接收是为了支持send),最后再加一个yield空值
        yield
    
    g = generator4()
    ret = g.__next__()
    print('***', ret)
    ret = g.send('hello')  # send的效果和next一样,都会返回yield的值
    print('***', ret)
    # 123
    # *** 1
    # ======= hello
    # 456
    # *** 2
    

    send 获取下一个值的效果和next基本一致,也会返回yield的值;
    只是在获取下一个值的时候,给上一yield的接受位置传递一个数据(所以在send之前,一定要有一次返回yield的操作(即一次next))
    最后一个yield不能接受外部的值

  • 添加装饰器(承接上一段代码)

    看到在生成器在使用时,需要进行一步没有实用__next__的操作,如果写了一两个生成器,每次追加一步__next__操作还可以接受,但是如果很多的话就不免麻烦了,通过设置装饰器的方式可以统一为这些函数加上__next__

    # 预激生成器的装饰器(承接上一个函数,就是用装饰器做了__next__的操作,下面用的时候可以直接send)
    def init(func):   #装饰器
        def inner(*args,**kwargs):
            g = func(*args,**kwargs)    #g = average()
            g.__next__()
            return g
        return inner
    
    @init
    def generator4():
        print(123)
        content = yield 1   # 这个yield返回之后,执行send操作,赋值给content
        print('=======', content)
        print(456)
        arg = yield '这是实际用到的最后一个yield了'
        print('这里是最后一个yield之后的一些操作')
        # 最后一个yield之后不应再有操作,否则报错
        # 可以把最后一个yield写成上面的形式(用一个变量来接收是为了支持send),最后再加一个yield空值
        yield
    
    g = generator4()
    ret = g.send('hello')  # send的效果和next一样,都会返回yield的值
    print('***', ret)
    # 123
    # ======= hello
    # 456
    # *** 这是实际用到的最后一个yield了
    
  • yield from

    在python3中,出现了一种yield from的新写法,感觉它就行for i in xxx一样是个方便的用来遍历的操作

    # 普通写法
    def generator5():
        a = 'abcde'
        b = '12345'
        for i in a:
            yield i
        for i in b:
            yield i
    # yield from写法
    def generator6():
        a = 'abcde'
        b = '12345'
        yield from a
        yield from b
    
    g5 = generator5()
    for i in g5:
        print(i, end=' ')
    print()
    # a b c d e 1 2 3 4 5 
    
    g6 = generator6()
    for i in g6:
        print(i, end=' ')
    print()
    # a b c d e 1 2 3 4 5 
    
  • 参考文献

    生成器,内置函数Ⅰ

发布了157 篇原创文章 · 获赞 163 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/BBJG_001/article/details/104709985