• Python-生成器


    1、生成器***

      之前在列表解析中已经介绍了 生成器表达式。这里介绍生成器函数。

      生成器:generator

        生成器指的是生成器对象,可以有生成器表达式得到,可以使用yield 关键字得到一个生成器函数,调用这个函数就得到一个生成器对象。

      生成器函数

        函数体重包含yield语句 的函数,返回生成器对象

        生成器对象,是一个可迭代对象,是一个迭代器。

        生成器对象,是惰性求值的

        举例 1:

     1 def fn():
     2     for i in range(5):
     3         yield i
     4 
     5 print(type(fn())) # <class 'generator'>
     6 
     7 for x in fn():
     8     print(x)
     9 print('-------------------------')    
    10 for x in fn():# 这个第二次还能继续循环迭代是因为第二次循环又重新调用了fn(),作为一个生成器对象
    11     print(x)
    12 print('-------------------------')
    13 
    14 g = fn() #
    15 
    16 for x in g:
    17     print(x)
    18 print('-------------------------')    
    19 for x in g: # 还是从之前的生成器中继续迭代
    20     print(x)

         举例2:

     1 def fen():
     2     print('line 1')
     3     yield 1
     4     print('line 2')
     5     yield 2
     6     print('line 3')
     7     for i in range(5):
     8         print(i)
     9     return 3
    10 g = fen()
    11 
    12 count = 0
    13 for x in g:
    14     count += 1
    15     print(x,count)
    16 
    17 # line 1
    18 # 1 1
    19 # line 2
    20 # 2 2
    21 # line 3
    22 # 0
    23 # 1
    24 # 2
    25 # 3
    26 # 4

         总结:

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

         生成器函数总结

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

         举例 3:

     1 def counter():
     2     i = 0
     3     while True:
     4         i += 1
     5         yield i
     6 def inc(c):
     7     return next(c)
     8 
     9 c = counter() #每次都要外部传参
    10 print(inc(c)) # 1
    11 print(inc(c)) # 2
    12 
    13 def counter():
    14     i = 0
    15     while True:
    16         i += 1
    17         yield i
    18 def inc():
    19     c = counter() # 每次都重新调用,所以每次都拿到同样的值
    20     return next(c)
    21 
    22 print(inc()) # 1
    23 print(inc()) # 1
    24 print(inc()) # 1

         举例 4:

     1 '''
     2     上面的优化:
     3         1、不需要外部传参,感觉 inc() 像一个生成器对象
     4         2、内层函数作为一个生成器函数,并且在同级进行调用,作为生成器对象
     5         3、外层函数将生成器对象地址返回给 外层函数
     6         4、全局调用外层函数,就相当于是一个生成器对象。
     7 '''
     8 def inc():
     9     def countes():
    10         i = 0
    11         while True:
    12             i += 1
    13             yield i
    14     c = countes()
    15     return lambda :next(c)
    16 
    17 foo = inc()
    18 print((foo())) # 1
    19 print((foo())) # 2

         举例 5:

     1 def fib(n):
     2     a = 0
     3     b = 1
     4     for i in range(n):
     5         a, b = b, a + b
     6         yield a
     7 
     8 foo = fib(5)
     9 # for _ in range(5):
    10 #     print(next(foo))
    11 
    12 for i in foo:
    13     print(i)
    14 
    15 
    16 
    17 def fib():
    18     x = 0
    19     y = 1
    20     while True:
    21         yield y
    22         x, y = y, x + y
    23 
    24 foo = fib()
    25 for _ in range(5):
    26     print(next(foo))
    27 
    28 print('-------')
    29 
    30 for _ in range(10):
    31     # next(foo)
    32     print(next(foo),'--')
    33 
    34 # 1
    35 # 1
    36 # 2
    37 # 3
    38 # 5
    39 # -------
    40 # 8 --
    41 # 13 --
    42 # 21 --
    43 # 34 --
    44 # 55 --
    45 # 89 --
    46 # 144 --
    47 # 233 --
    48 # 377 --
    49 # 610 --

      生成器应用:yield引出的(遇到yield,会让出控制权)

      • 协程Co-routine
        • 生成器的高级用法
        • 比进程、线程轻量级
        • 是在用户空间调度函数的一种实现
        • Python3 asyncIO 就是协程实现,已经加入标准库
        • Python3.5 使用async,await关键字直接原生支持协程
        • 协程调度器实现思路:
          • 有两个生成器A,B
          • next(A) 后,A 执行到了yield 语句暂停,然后去执行next(B),B执行到yield 语句也暂停,然后再次调用next(A),再调用next(B),周而复始,就实现了调度的效果,
          •  1 # 在用户空间就做了调度
             2 def a():
             3     for i in range(5):
             4         yield i
             5 
             6 def b():
             7     for i in range(5):
             8         yield i
             9 
            10 a = a()
            11 b = b()
            12 
            13 for i in range(10):
            14     if i % 2 == 0:
            15         print(next(a), 'a')
            16     else:
            17         print(next(b), 'b')
            18 # 0 a
            19 # 0 b
            20 # 1 a
            21 # 1 b
            22 # 2 a
            23 # 2 b
            24 # 3 a
            25 # 3 b
            26 # 4 a
            27 # 4 b
            协程mode
          • 可以引入调度的策略来实现切换的方式
        • 协程是一种非抢占式调度
        • 协程效率是比较高的

       yield from:

    1 def inc():
    2     for x in range(100):
    3         yield x
    4         
    5         ||
    6         ||
    7         
    8 def inc():
    9     yield  from range(100)

      yield from 是Python3.3 出现的新的语法

      yield from iteable 是 for item in iterable : yield item 形式的语法糖

        从 可迭代 对象中一个个拿 元素   

     1 def counter(n):
     2     for x in range(n):
     3         yield x
     4 
     5 def inc(n):
     6     yield  from counter(n)
     7 
     8 foo = inc(10)
     9 
    10 print(next(foo)) # 0
    11 print(next(foo)) # 1

    2、send触发yield返回值原理

     1 def test():
     2     print('开始啦')
     3     firt = yield 1      # return 1,first=None
     4     print('第一次', firt)
     5     yield 2
     6     print('第二次')
     7 
     8 t = test()
     9 # print(next(t)) # next(t)
    10 # print('--------------')
    11 # print(next(t)) # next(t)
    12 # print(next(t,'end')) # next(t)
    13 res=t.send(None) # 第一次进入后,没有接受值的 标识符,所以传入None
    14 
    15 print(res)
    16 
    17 res=t.send(10)
    18 print(res)
    为什么要坚持,想一想当初!
  • 相关阅读:
    【脑图】iOS的Crash分类和捕获
    Ruby03
    Ruby02
    Ruby01
    如何快速把一个十进制数转换为二进制?
    iOS
    互联网协议基本知识
    XCBB
    iOS
    iOS
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9533134.html
Copyright © 2020-2023  润新知