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

    生成器:generator,在Python中, 一边循环一边计算的机制, 称为生成器: generator

    Python2很多列表的地方,在Python3被更新为生成器
    可以基于生成器直接创建列表
    filter
    map
    1、如何创建生成器?
    1.1 g1 = (x for x in range(10) if x % 2 == 0)
    1.2 g2 = func1()
    函数func1中必须包含yield关键字
    2、如何生成数据?(下蛋的鸡)
    特征:
    2.1 必须先生第一个,才能生第二个
    2.2 必须是一个一个来
    生成语法:
    a.next(g)
    b.g.__next__()
    c.g.send(value)
    value 在生成器开始的时候,只能给None
    后续可以给随意参数
    如果超出生成数据范围,会导致异常 StopIteration

    3、生成器的好处?
    3.1 时间开销
    3.2 内存开销
    def generator():
        print("a")
        count = yield 1
        print("---->",count)
        print('b')
        yield 2
    
    
    g = generator()
    print(next(g))
    
    res = g.send('123')
    print(res)
    print("- -"*10)
    
    lis = [1,2,3,4,5,6,7]
    lis1 = [2,3,4,5,6,7,8]
    li = list(map(lambda x,y:x,lis,lis1))
    for i in li:
        print(i)
    
    
    g2 = (x for x in range(10) if x % 2 == 0)
    print(type(g2))
    # 3种使用方式
    v = next(g2)
    print(v)
    v = g2.__next__()
    print(v)
    v = g2.send(None)
    print(v)
    
    
    
    import time
    import sys
    """
    1M = 1024kb
    1kb = 1024byte
    1byte = 8bit
    """
    start = time.time()
    # list1 = [x for x in range(10000000)]
    list1 = (x for x in range(10000000))
    size = sys.getsizeof(list1)#字节
    end = time.time()
    print(f'耗时:{end-start}秒')
    print(f'list1占用内存{size/1024}kb')
    # print(f'list1占用内存{size/1024/1024}M') 

     运行结果

     迭代器

    • 迭代器: 拥有__iter__方法和__next__方法的对象就是迭代器   注意:生成器就是迭代器;可迭代对象不一定是迭代器
    • 可迭代性的元素:list, tuple, str, dict, set
    • itertion: 就是迭代,一个接一个(one after another),是一个通用的概念,比如一个循环遍历某个数组。

    • iterable: 这个是可迭代对象,属于python的名词,范围也很广,可重复迭代,满足如下其中之一的都是iterable:

      • 可以for循环: for i in iterable

      • 可以按index索引的对象,也就是定义了__getitem__方法,比如list,str;

      • 定义了__iter__方法。可以随意返回。

      • 可以调用iter(obj)的对象,并且返回一个iterator

    • iterator迭代器对象,也属于python的名词,只能迭代一次。需要满足如下的迭代器协议

      • 定义了__iter__方法,但是必须返回自身

      • 定义了next方法,在python3.x是__next__。用来返回下一个值,并且当没有数据了,抛出StopIteration

      • 可以保持当前的状态

    判断是否具有可迭代性(满足可迭代协议):

    (1)查看是否实现了__iter__方法

        "__iter__" in dir(可迭代性对象)

    (2)判断目标对象是否是可迭代性类实例,使用 isinstance(Iterable)来判断

        from collections.abc import Iterableisinstance(可迭代性对象, Iterable)

    for循环的本质

    • 通过__iter__()获取该对象的一个迭代器对象
    • 通过__next__()函数,依次获取下一个元素
    class MyRange:
        def __init__(self, stop):
            self.start = 0
            self.stop = stop
            self.step = 1
        
        def __iter__(self):
            while self.start < self.stop:
                yield self.start
                self.start += self.step
        
    for i in MyRange(5):
        print(i)
    

     

    迭代器的几个创建方法:

    1.生成器函数

     和普通函数的 return 返回不同,生成器函数使用 yield。

    >>> def odd_func(start=1, end=10):
    ...     for val in range(start, end + 1):
    ...         if val % 2 == 1:
    ...             yield val
    ...
    >>> of = odd_func(1, 5)
    >>> of
    <generator object odd_func at 0x101a14200>
    >>> iter(of)
    <generator object odd_func at 0x101a14200>
    >>> next(of)
    1
    >>> next(of)
    3
    >>> next(of)
    5
    >>> next(of)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    2.生成器表达式

    >>> g = (v for v in range(1, 5 + 1) if v % 2 == 1)
    >>> g
    <generator object <genexpr> at 0x101a142b0>
    >>> iter(g)
    <generator object <genexpr> at 0x101a142b0>
    >>> next(g)
    1
    >>> next(g)
    3
    >>> next(g)
    5
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    3.自定义迭代器

    基于模拟Range实现的IntegRange,封装一个类,可以通过for循环直接打印指定范围的质数
    # 例如:
    # for i in IntegerRange(2,20,1):
    # print(i)
    # 可以依次打印出2,3,5,7,11...等全为质数的数字,
    import math
    
    
    class IntegerRange:
        def __init__(self, start, end, step):
            self.start = start
            self.end = end
            self.step = step
    
        def __iter__(self):
            return self
    
        def __next__(self):
            while self.start < self.end:
                self.start += self.step
                if self.prime(self.start):
                    return self.start
            else:
                raise StopIteration("跑完了")
    
        def prime(self, n):
            if n <= 1:
                return 0
            for i in range(2, math.ceil(math.sqrt(n + 1))):
                if n % i == 0:
                    return 0
            return 1
    g = IntegerRange(2,20,1)
    print(g.__next__())
    print(next(g))
    

     怎么选择?

    到现在为止,我们知道了创建迭代器的 3 种方式,那么该如何选择?

    最简单的就是生成器表达式,如果表达式能满足需求,那么就是它;如果需要添加比较复杂的逻辑就选生成器函数;如果前两者没法满足需求,那就自定义类实现吧。总之,选择最简单的方式就行。 

    注意:迭代器遍历完一次就不能从头开始了

    >>> l = [1, 3, 5]
    >>> li = iter(l)
    >>> li
    <list_iterator object at 0x101a1da90>
    >>> 3 in li
    True
    >>> 3 in li
    False

    因为 li 是列表迭代器,第一次查找 3 的时候,找到了,所以返回 True,但是由于第一次迭代,已经跳过了 3 那个元素,第二次就找不到了,所以会出现 False。

    因此,记得迭代器是「一次性」的。

    总结:

    • 实现了迭代器协议的对象都是迭代器
    • 实现了 __iter__() 方法并返回迭代器的对象是可迭代对象
    • 生成器也是一种迭代器
    • 创建迭代器有三种方式,生成器表达式、生成器函数、自定义类,看情况选择最简单的就好
    • 迭代器同时也是可迭代对象
    • 迭代器是「一次性」的
  • 相关阅读:
    MongoDB:利用官方驱动改装为EF代码风格的MongoDB.Repository框架 二
    Ubuntu系统错误 没有公钥,无法验证下列签名: NO_PUBKEY 5F16B97C1AD28806
    Mysql数据库导出和导入
    Mysql清理binlog日志
    新手应该知道的流量概念
    xdebug对php程序性能分析
    mysql连接错误
    mysql导入导出命令
    mysql导出错误
    linux查看是软件是否安装
  • 原文地址:https://www.cnblogs.com/songdanlee/p/11191258.html
Copyright © 2011-2022 走看看