zoukankan      html  css  js  c++  java
  • Python 迭代器&生成器

    生成器

    • 通过列表生成式, 可以直接生成一个列表. 但是受到内存限制, 列表容量是有限的. 如果创建一个包含100万个元素的列表, 却只需要访问其中几个, 空间就浪费了.
    • 如果列表元素可以按照某种算法算出来, 在循环的过程中不断推算出后续的元素, 这样就不必创建完整的list,从而节省大量空间. 在Python中, 这种一边循环一边计算的机制, 称为生成器: generator.

    创建一个generator, 有很多种方法

    • 第一种方法: 把一个列表生成式的 [ ] 改成 (), 就创建了一个generator
      • 1 >>> L = [x*x for x in range(10)]
        2 >>> L
        3 
        4 >>> g = (x*x for x in range(10))
        5 >>> g
      •  1 #!/usr/bin/python
         2 # -*- coding: utf-8 -*-
         3 
         4 a = []
         5 for i in range(10):
         6 a.append(i*2)
         7 
         8 print(a)
         9 
        10 
        11 print("========== 上述代码等效于下面这句 ========== ")
        12 b = [i*2 for i in range(10)]
        13 print(b)
        14 
        15 
        16 print("============== 更进阶写法 ============== ")
        17 c = [func(i) for i in range(10)]
        18 print(c)
        View Code
      • 注: 其实生成器产没有直接把数据都计算出来, 只是生成了一个地址, 这个地址包含的是计算的方法(下图方法2).调用的时候才会开始产生值.
      •  生成器只有调用的时候才会生成一个个的值, 所以直接像列表一样取某个位置上的值是不行的. 所以生成器是不支持列表的切片等值的.只能通过循环取出具体的值.

      • 生成器只记住当前的位置, 是没有办法往回取值的(比如打了两个__next__()之后想取前边第一个值,是不行的).只能取下一个值.
    • 第二种方法, 用一个函数做生成器
      • 斐波那契数列 (要在哪里返回数据,就在哪里用yield. yield保存了函数中断的点,一旦调用__next__方法, 函数又会从中断点开始继续执行)
        •  1 # !/user/bin/python
           2 # -*- coding: utf-8 -*-
           3 
           4 def fib(max):
           5     n,a,b = 0,0.1
           6     while n<max:
           7         print(b)
           8         a,b = b, a+b
           9         n = n + 1
          10     return 'done'
          11 
          12 fib(10)
          13 
          14 
          15 
          16 # 生成器
          17 def fib(max):
          18     n,a,b = 0,0.1
          19     while n<max:
          20         yield b
          21         a,b = b, a+b
          22         n = n + 1
          23     return 'done'
          24 
          25 print(fib(10))  # 因为fib()是个生成器, 这样只能打印出一个地址. 要想打印出数值,需要用循环,或者___next___()
          26 
          27 f=fib(100)
          28 print(f.__next__())   # 这种方式 ,可以在循环中断在某个地方做些其它的事再回来.
          29 print('============')
          30 print(f.__next__())
          31 
          32 print('======================== loop ========================')
          33 for i in f:
          34     print(i)  # 不会从头开始打印,因为前面有两个print(f.__next__())
          View Code
        • 抓取异常
        •  1 # !/user/bin/python
           2 # -*- coding: utf-8 -*-
           3 
           4 def fib(max):
           5     n,a,b = 0,0.1
           6     while n<max:
           7         print(b)
           8         a,b = b, a+b
           9         n = n + 1
          10     return 'done'
          11 
          12 fib(10)
          13 
          14 
          15 
          16 # 生成器
          17 def fib(max):
          18     n,a,b = 0,0.1
          19     while n<max:
          20         yield b
          21         a,b = b, a+b
          22         n = n + 1
          23     return 'done'
          24 
          25 print(fib(10))  # 因为fib()是个生成器, 这样只能打印出一个地址. 要想打印出数值,需要用循环,或者___next___()
          26 
          27 f=fib(100)
          28 print(f.__next__())   # 这种方式 ,可以在循环中断在某个地方做些其它的事再回来.
          29 print('============')
          30 print(f.__next__())
          31 
          32 print('======================== loop ========================')
          33 for i in f:
          34     print(i)  # 不会从头开始打印,因为前面有两个print(f.__next__())
          35 
          36 
          37 #  抓取异常
          38 f=fib(10)
          39 g=fib(6)
          40 while True:
          41     try:
          42         x = next(g)
          43         print('g: ', x)
          44     except StopIterration as e:
          45         print('Generator return  value: ', e.value)
          46         break
          View Code

     生成器并行运算

     1 # !/user/bin/python
     2 # -*- coding: utf-8 -*-
     3 import time
     4 
     5 def consumer(name):
     6     print('%s 准备吃包子了' %name)
     7     while True:
     8         baozi = yield
     9         print('包子[%s] 来了, 被[%s]吃了' %(baozi, name))
    10 
    11 
    12 c = consumer('lucy')
    13 c.__next__()  # 输出第一个print的内容  print('%s 准备吃包子了' %name)
    14 c.__next__()  # 输出第二个print的内容, print('包子[%s] 来了, 被[%s]吃了' %(baozi, name))
    15 b1 = '韭菜'
    16 c.send(b1)  # 把包子的参数传过去,被yield接收到,传给baozi.  # 返回包子[韭菜] 来了, 被[lucy]吃了
    17 
    18 '''
    19 send和next的区别: send唤醒生成器继续打印,并且会把参数传给yield; next只能唤醒生成器, 不能传值.
    20 '''
    21 
    22 # 单线程下的并行交换, 也叫携程.
    23 
    24 def producer(name):
    25     c = consumer('A')
    26     c2 = consumer('B')
    27     c.__next__()
    28     c2.__next__()
    29     print('老子开始准备做包子了')
    30     for i in range(10):
    31         time.sleep(1)
    32         print('做了1个包子,分两半')
    33         c.send(i)
    34         c2.send(i)
    35 
    36 
    37 producer('alex')

    迭代器

    可直接作用于for循环的数据类型有以下几种:

    a. 一类是集合数据类型, 如list, tuple, dict, set, str等

    b. 一类是generator, 包括生成器和带yield的generator function 

    这些可以直接作用于for循环的对象统称为可迭代对象: Iterable.

    可以用例isinstance()判断一个对象是否是Iterable对象.

    1 from collections import Iterable
    2 
    3 isinstance([],Iterable)
    4 isinstance({ },Iterable)
    5 isinstance('AB',Iterable)
    6 isinstance((x for x in range(10)), Iterable)
    7 isinstance(100, Iterable)

    生成器不但可以作用于For循环, 还可以被next() 函数不断调用 并返回下一个值, 直到最后抛出StopIteration错误表示无法继续返回下一个值了.

    可以被next()函数调用并不断返回下一个值的对象称为换代器: Iterator.

    可以使用isInstance()判断一个对象是否是Iterator对象:

     1 from collections import Iterable
     2 
     3 isinstance([],Iterable)  # True
     4 isinstance({ },Iterable)  # True
     5 isinstance('AB',Iterable)  # True
     6 isinstance((x for x in range(10)), Iterable)  # True
     7 isinstance(100, Iterable)  # True
     8 
     9 
    10 from collections import Iterator  # (没有__next()__方法就不是迭代器):
    11 isinstance((x for x in range(10)), Iterator)  # True
    12 isinstance([], Iterator)  # False
    13 isinstance((), Iterator)  # False
    14 isinstance('ab', Iterator)  # False
    15 
    16 
    17 '''
    18 生成器都是Iterator对象, 但list, dict, str是Iterable, 却不是Iterator.
    19  把list, dict, str等Iterable变成Iterator可以使用iter()函数
    20 '''
  • 相关阅读:
    [调参]batch_size的选择
    [调参]CV炼丹技巧/经验
    [Pytorch]Pytorch加载预训练模型(转)
    [PyTorch]论文pytorch复现中遇到的BUG
    [Opencv]图像的梯度与边缘检测(转)
    freemodbus移植、实例及其测试方法
    eclipse的C/C++开发搭建
    ROS安装
    U-boot移植
    QT开发实战一:图片显示
  • 原文地址:https://www.cnblogs.com/cheese320/p/8968983.html
Copyright © 2011-2022 走看看