• python 生成器


    生成器(generator)

         在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。生成器本身就是迭代器。

    1 生成器表达式

    生成器表达式的语法和列表生成式的一样,只不过把列表生成式的[]换成()。

    gen=(x+y for x in ("A","B","C") for y in ("a","b","c"))
    print(gen)
    print(next(gen))
    print(next(gen))
    
    result:
    <generator object generator at 0x00000203D50FF468>
    Aa
    Ab
    
    

    2 生成器函数

    在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数。

    yield的作用:

    1. yield把函数变成生成器(把__iter__()和__next__()封装到函数里)
    2. yield能让函数挂起,并保存函数当前的运行状态。
    3. yield能返回值(这一点和return类型)

    yield和return的区别:
    return返回一次值,函数就结束运行。而yield能多次返回值。

    • 有了yield这样灵活的语法,我们就能自己定义生成器了。
    from collections import Iterator
    def func(n):
        i=0
        while i<=n:
            yield i
            i+=2
    g=func(10)
    if isinstance(g,Iterator):
        print(next(g),end=" ")
        print(next(g),end=" ")
        print(next(g),end=" ")
        print(next(g),end=" ")
        print(next(g),end=" ")
        print(next(g),end=" ")
        print(next(g),end=" ")
    else:
        print(g)
    
    
    result:
    Traceback (most recent call last):
    0 2 4 6 8 10   File "D:/devtools/workspace/python/PycharmProjects/py_fulstack_s4/day23/yield用法.py", line 19, in <module>
        print(next(g),end=" ")
    StopIteration
    

    每次运行遇到yield先执行再挂起,并可以通过next()方法来获取其返回值,然后继续向下运行,直到遇到下一个yield挂起并返回。直到遇到StopIteration停止。

    改用for遍历:

    if isinstance(g,Iterator):
        for i in g:
            print(i, end=" ")
    else:
        print(g)
    
    • 每一次调用生成器函数返回一个生成器对象,调用同一个生成器函数返回的多个生成器对象互相之间不影响。
    def func():
        pass
    a=func()
    b=func()
    print(a is b)   #True
    def generator():
        yield 1
    g=generator
    print(g)   #<function generator at 0x0000020A119E3EA0>
    g1=generator()
    print(g1)   #<generator object generator at 0x0000020A11E2F410>
    g2=generator()
    print(g2)   #<generator object generator at 0x0000020A11E2F1A8>
    print(g1 is g2)   #False
    

    g是函数生成器的地址,而g1和g2是生成器对象的地址。可以看出同一个函数生成器调用后赋值给多个变量,这些变量是互不受影响的。

    • 如何接收另一个生成器函数的迭代。通过from关键字来实现
    def counter(start=0):
        while True:
           yield start
           start += 1
    
    def gen():
        yield 1
        yield 2
        yield from counter(10)
    
    g=gen()
    
    for i in range(10):
        print(next(g),end=" ")
    

    结果:

    1 2 10 11 12 13 14 15 16 17 
    

    3 生成器常用的方法

    • close() 关闭生成器,关闭以后再调用next()方法会报出StopIteration。
    li=(x for x in range(10) if x%2==0)
    print(next(li))
    print(next(li))
    li.close()
    print(next(li))
    
    result:
    Traceback (most recent call last):
      File "D:/devtools/workspace/python/PycharmProjects/py_fulstack_s4/day23/yield用法.py", line 14, in <module>
        print(next(li))
    StopIteration
    0
    2
    
    • throws()用来向生成器函数送入一个异常,可以结束系统定义的异常,或者自定义的异常。
      throw()后直接抛出异常并结束程序,或者消耗掉一个yield,或者在没有下一个yield的时候直接进行到程序的结尾。
    def gen():
        while True:
            try:
                yield "value 1"
                yield "value 2"
                print("here!")
            except ValueError:
                print("the ValueError is here")
            except TypeError:
                break
    g=gen()
    print(next(g))
    print(g.throw(ValueError))
    print(next(g))
    print(g.throw(TypeError))
    

    result:

    value 1
    the ValueError is here
    Traceback (most recent call last):
    value 1
    value 2
      File "D:/devtools/workspace/python/PycharmProjects/py_fulstack_s4/day23/gen.py", line 18, in <module>
        print(g.throw(TypeError))
    StopIteration
    
    

    执行过程:

    1. print(next(g)):输出value 1,并挂起。
    2. 由于执行了g.throw(ValueError),所以会跳过所有后续的try语句,也就是说yield ‘value 2’不会被执行,然后进入到except语句,打印出the ValueError is here。然后再次进入到while语句部分,消耗一个yield,所以会输出value 1。
    3. print(next(g)),会执行yield ‘alue 2’语句,并挂起。
    4. g.throw(TypeError):会跳出try语句,从而print(‘here!’)不会被执行,然后执行break语句,跳出while循环,然后到达程序结尾,所以跑出StopIteration异常。

    5 yeild在协程中的使用

    send()接受外部传入的一个变量,并根据变量内容计算结果后返回接受外部传入的一个变量,并根据变量内容计算结果后返回

    def func(name):
        print("%s 开始点餐!"%(name))
        food_menu=[]
        while True:
            food=yield food_menu
            food_menu.append(food)
            print("%s 的菜单是:%s"%(name,food_menu))
        print("完成点餐!")
    g=func("egg")
    print(next(g))
    print(g.send("西红柿炒番茄"))
    print(g.send("白菜炒包菜"))
    
    
    result:
    egg 开始点餐!
    []
    egg 的菜单是:['西红柿炒番茄']
    ['西红柿炒番茄']
    egg 的菜单是:['西红柿炒番茄', '白菜炒包菜']
    ['西红柿炒番茄', '白菜炒包菜']
    
    1. g.send(None)或者next(g)可以启动生成器函数并执行到第一个yield语句结束的位置。并执行到第一个yield语句结束的位置。此时food_menu没有值,所以返回为[]。如果去掉next(g),程序会报错TypeError: can't send non-None value to a just-started generator。
    2. 当运行代码g.send("西红柿炒番茄"),实际上是把"西红柿炒番茄"赋值给food,而g.send()的返回值就是yield后面跟着的food_menu。输出结果:['西红柿炒番茄']
    3. 重复第2步,输出:['西红柿炒番茄', '白菜炒包菜']。

    其他生成器链接:http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html

  • 相关阅读:
    穿透层的鼠标事件
    深入浅出HTML与XHTML的区别
    JQuery中一个简单的表单验证的实例
    JavaScript window.setTimeout() 的详细用法
    js动态创建及移除div的方法
    js插入节点appendChild和insertBefore
    sublime使用方法
    js移动客户端--触屏滑动事件
    jquery 延迟执行实例介绍
    JS页面延迟执行一些方法(整理)
  • 原文地址:https://www.cnblogs.com/yangzhenwei123/p/6759232.html
Copyright © 2020-2023  润新知