• [ python ] 迭代器和生成器


     列表生成式

      列表生成式是 python 内置的非常简单却强大的可以用来创建list的生成式。

    有这样一个需求:
        l1 = [1,2,3,4,5,6,7,8,9]    循环每个元素加1

    l1 = [1,2,3,4,5,6,7,8,9]
    
    # 使用列表生成式将列表中的各个元素加1
    list_num = [x+1 for x in l1]	# 这里就是一个列表生成式
    print(list_num)
    

    列表生成式可以用一行语句代替循环生成上面的list

     迭代器

        迭代器表面上看是一个数据流对象或容器,当使用其中的数据时,每次从数据流中取出一个数据,直到数据被取完,而且数据不会被重复使用。
        从代码的角度来看,迭代器是实现了迭代器协议方法的对象和类。
        迭代器协议方法主要是两个:
            __iter__(): 该方法返回对象本身,它是for语言使用迭代器的要求,只要函数含有__iter__就可以说这个函数是可迭代的;
            __next__(): 该方法用于返回容器中下一个元素或数据。当容器中的数据用尽时,应该引发 StopIteration 异常一个类只要具有这两种方法,就可以称之为 迭代器,也可以说是可迭代的。

    s1 = 'hello world'
    print('__iter__' in dir(s1))
    print('__next__' in dir(s1))
    
    # 字符串s1包含 __iter__ 方法且不包含__next__方法,所以字符串 s1 只是一个可迭代的类型,并不是一个迭代器
    
    # 执行结果:
    # True
    # False
    
    s1 = 'hello world'
    s2 = s1.__iter__()  # 将可迭代类型转换为 迭代器 使用 __iter__()
    print('__iter__' in dir(s2))
    print('__next__' in dir(s2))
    
    # 使用 __iter__()方法将 s1 字符串转换为迭代器,迭代器既有__iter__方法,又有 __next__方法
    # 执行结果:
    # True
    # True
    

    自定义一个迭代器必须满足:
        类中必须要定义 __iter__ 方法和 __next__方法

    # 自定义一个迭代器:
    
    class My_iterator(object):
        def __init__(self, x, max):
            self.mul, self.x = x, x
            self.xmax = max
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.x and self.x !=1:
                self.mul = self.mul + self.x
                if self.mul < self.xmax:
                    return self.mul
                else:
                    raise StopIteration
    
    if __name__ == '__main__':
        myite1 = My_iterator(2, 100)
        for i in myite1:
            print(i)
    

    迭代器一定是可迭代的, 但是可迭代的不一定是迭代器

     生成器

      使用生成器可以生成一个值的序列用于迭代,并且这个值的序列不是一次生成的,而是使用一个,再生成一个,可以使得程序节约大量内存。
        生成器对象是通过yield关键字定义的函数对象,因此生成器也是一个函数。生成器用于生成一个值的序列,以便在迭代中使用。

    自定义生成器:

    def foo():
        print('1111')
        yield 1
        print('22222')
        yield 2
    
    f = foo()
    print('type f:', type(f))
    print(f.__next__())
    print(f.__next__())
    
    # 执行结果:
    # type f: <class 'generator'>
    # 1111
    # 1
    # 22222
    # 2
    

    执行流程如下图:

    需要注意的是 yield 是生成器中的关键字,生成器在实例化的时候并不会立即执行,而是等待调用其__next__()方法之后才开始运行,当再次调用__next__()方法会在第一次yield返回值的最后开始执行,不断的调用__next__()方法,直到最终返回 StopIteration 异常为止。

    实例1:移动平均值

    # 移动平均值
    
    def foo():
        '''
        sum 计算总和
        count 计算有几个数
        avg 平均数
        :yield: 返回计算出的平均数 
        '''
        sum = 0
        count = 0
        avg = 0
        while True:
            num = yield avg # 接收num,返回avg
            sum += num
            count += 1
            avg = sum / count
    
    
    f = foo()
    next(f)
    ret = f.send(10)
    print(ret)
    ret = f.send(20)
    print(ret)
    ret = f.send(30)
    print(ret)
    ret = f.send(40)
    print(ret)
    
    # 执行结果:
    # 10.0
    # 15.0
    # 20.0
    # 25.0
    移动平均值
  • 相关阅读:
    Linux文件名匹配
    Linux的常用命令
    百度飞桨学习笔记【Windows下用anaconda安装飞桨】
    在python中调用shell命令获得返回值
    使用sratoolkit下载NCBI数据
    perl 打开gz压缩文件 输出gz压缩文件
    jupyter notebook安装教程,打开ipynb文件
    生物信息学相关网站和博客资源
    R的循环补齐功能
    perl 遍历目录并且对目录中的文件进行操作
  • 原文地址:https://www.cnblogs.com/hukey/p/9698150.html
Copyright © 2020-2023  润新知