zoukankan      html  css  js  c++  java
  • 生成器与迭代器的使用规则

    斐波拉契数列

     1 def fib(max):
     2     n,a,b = 0,0,1
     3     while n < max:
     4         print(b)
     5         a,b = b,a+b
     6         n = n + 1
     7     return 'done'
     8 
     9 
    10 fib(10)
    11 #注意赋值语句:a,b = b,a+b
    12 
    13 
    14 a,b = b,a+b
    15 1,1 = 1,0+1
    16 1 ,2 = 1,1+1
    17 2,3  =  2,1+2
    18 3,5  = 3,2+3
    19 5,8  = 5,3+5
    20 8,13 = 8,5+8
    21 13,21= 13,8+13
    菲波那切数列

    用函数变成生成器修改斐波拉契数列

     1 #将print改为yeild:
     2 def fib(max):
     3     n,a,b = 0,0,1
     4     while n < max:
     5         #print(b)
     6         yield b
     7         a,b = b,a+b
     8         n = n + 1
     9     return 'done'
    10 
    11 ret = fib(10)
    12 print(ret)
    13 
    14 
    15 #显示结果:
    16 <generator object fib at 0x0000000000B387D8>
    斐波那契数列生成器

    生成器的调用

    每执行一个ret.__next__(),就调用一次。


    一、优点:

    每一次调用就会中断退出,然后在调用在退出,以此类推。
    例如:每调用一次,程序就会退出,然后在去做别的事儿,做完在用ret.__next__(),调用下一个生成器。

     1 def fib(max):
     2     n,a,b = 0,0,1
     3     while n < max:
     4         #print(b)
     5         yield b
     6         a,b = b,a+b
     7         n = n + 1
     8     return 'done'
     9 
    10 ret = fib(10)
    11 print(ret)
    12 print(ret.__next__())
    13 print(ret.__next__())
    14 print(ret.__next__())
    调用生成器实例

    二、缺点:

    __next__()调用超出迭代器的范围,所以报错。
    生产中是不知道迭代器的元素有多少,所以只能等待异常的出现。

    因此可以用异常处理来抓住生成器的结束,如下:

     1 def fib(max):        1   6
     2     n,a,b = 0,0,1    7
     3     while n < max:   8  16
     4         #print(b)
     5         yield b       9  13  17 #中断退出,并将至返回给next()
     6         a,b = b,a+b  14
     7         n = n + 1    15
     8     return '异常'
     9 
    10 g = fib(6)       2
    11 
    12 while True:       3    11
    13     try:          4
    14         #内置方法,与__next__()是一样的,返回到上一次yield中断的地方
    15         x = next(g)   5  12
    16         print('g:',x)  10  18
    17     except  StopIteration as  e:
    18         print('Generator return values:',e.value)
    19         break
    生成器异常处理的执行顺序

    协程

    一、概念:cpu调用程序分为:进程--(包含多个)-->线程--(包含多个)-->协程

    二、作用:通过生成器yield实现单线程的情况下实现并发运算效果(异步IO的雏形)。

    三、工作原理:

    1、生成器只有在调用时才会生成相应的数据
    2、调用方式有 " str__next__.()   str.send() "3、并且每调用一次就产生一个值调用到最后一个值后会报错
    4、报错可用try和except做异常处理
     
    四、注意事项:
    next:是直接调用yield,并不会传值。
    send:是调用并直接传值给yield。

    五、实例:

     1 #!/usr/bin/env python
     2 # -*- coding:utf8 -*-
     3 # Author:Dong Ye
     4 
     5 
     6 '''
     7 定义两个模型:
     8 一个是生产包子的。(生成器)
     9 另一个是吃包子的。(迭代器)
    10 
    11 这段功能实现了异步IO的雏形,也是一个简单的协程处理方式。
    12 协程的特点:实际是串行方式分开执行的,但由于运行效果快,给人的感觉像是并行。
    13 因此,协程也叫作:单线程下的并行执行效果。
    14 协程是包含在线程里的一个单位,线程时进程的一个单位。
    15 例如:enginx在异步单线程下,比多线程要快好多倍,也就是这种效果。
    16 '''
    17 
    18 import time
    19 
    20 
    21 #吃包子的
    22 def consumer(name):
    23     print('%s 准备吃包子了!' % name)
    24     while True:
    25         baozi = yield
    26         print("包子[%s]来了。被[%s]吃了!" %(baozi,name))
    27 
    28 
    29 #生产包子的
    30 def producer(name):
    31     #先定义2个协程(消费者)#将函数变成生成器
    32     c1 = consumer('A')   #2个消费者
    33     c2 = consumer('B')   #相当于2个协程(进程,线程,协程)
    34     #开始调用生成器初始化(准备吃包子)
    35     c1.__next__()     #开始调用生成器,只有next的时候才会到yield进行下一个操作
    36     c2.__next__()
    37     print('老子开始吃包子拉!')
    38     #循环的次数,每次循环都会传值给生成器(产生什么样的包子)
    39     for i in range(10):
    40         time.sleep(1)
    41         print("做了一个包子,分2半,一人一半")
    42         c1.send(i) #包子的类型
    43         c2.send(i)
    44 
    45 
    46 producer("alex")
    47 
    48 
    49 
    50 '''
    51 #手动做包子:
    52 c = consumer("dy")
    53 c.__next__()
    54 #c.__next__()
    55 
    56 b1 = "韭菜馅"
    57 c.send(b1)     #调用+传值
    58 #c.__next__()  #只调用,不传值
    59 '''
    60 
    61 
    62 
    63 显示结果:
    64 A 准备吃包子了!
    65 B 准备吃包子了!
    66 老子开始吃包子拉!
    67 做了一个包子,分2半,一人一半  #任务1
    68 包子[0]来了。被[A]吃了!      #任务2
    69 包子[0]来了。被[B]吃了!      #任务3
    70 做了一个包子,分2半,一人一半
    71 包子[1]来了。被[A]吃了!
    72 包子[1]来了。被[B]吃了!
    73 做了一个包子,分2半,一人一半
    74 包子[2]来了。被[A]吃了!
    75 包子[2]来了。被[B]吃了!
    76 做了一个包子,分2半,一人一半
    77 包子[3]来了。被[A]吃了!
    78 包子[3]来了。被[B]吃了!
    79 做了一个包子,分2半,一人一半
    80 包子[4]来了。被[A]吃了!
    81 包子[4]来了。被[B]吃了!
    82 做了一个包子,分2半,一人一半
    83 包子[5]来了。被[A]吃了!
    84 包子[5]来了。被[B]吃了!
    85 做了一个包子,分2半,一人一半
    86 包子[6]来了。被[A]吃了!
    87 包子[6]来了。被[B]吃了!
    88 做了一个包子,分2半,一人一半
    89 包子[7]来了。被[A]吃了!
    90 包子[7]来了。被[B]吃了!
    91 做了一个包子,分2半,一人一半
    92 包子[8]来了。被[A]吃了!
    93 包子[8]来了。被[B]吃了!
    94 做了一个包子,分2半,一人一半
    95 包子[9]来了。被[A]吃了!
    96 包子[9]来了。被[B]吃了!
    异步IO的雏形
  • 相关阅读:
    【学习笔记 2】单调队列 & 单调栈
    【学习笔记 1】快速幂
    题解P1151
    题解 P6161【[Cnoi2020]高维】
    不知道叫啥的题目1
    神秘题目1
    5.30 模拟赛赛后总结
    矩阵乘法加速图上问题专题总结
    点分治&点分树 复习
    5.26赛后总结
  • 原文地址:https://www.cnblogs.com/abobo/p/8110469.html
Copyright © 2011-2022 走看看