zoukankan      html  css  js  c++  java
  • python全栈闯关--13-迭代器和生成器

     1、迭代器

    可迭代协议

      含有双下划线方法__iter__()方法的都是可迭代

    迭代器协议

      内部含有__next__和__iter__方法的就是迭代器

    # 判断是否函数__iter__方法
    print("__iter__" in dir(int))
    print("__iter__" in dir(bool))
    print("__iter__" in dir(list))
    print("__iter__" in dir(dict))
    print("__iter__" in dir(set))
    print("__iter__" in dir(tuple))
    print("__iter__" in dir(enumerate([])))
    print("__iter__" in dir(range(1)))
    print([])
    print([].__iter__())  # 使用__iter__方法后,返回值为一个迭代器
    print(set(dir([].__iter__())) - set(dir([])))  # {'__setstate__', '__length_hint__', '__next__'}
    print([1, 2, 'aas', 'a'].__iter__().__length_hint__())  # 返回元素的个数
    
    # 迭代器使用next方法,可以遍历值
    l = [1, 2, 3, 4]
    iterator = l.__iter__()
    print(iterator.__next__())
    print(iterator.__next__())
    print(iterator.__next__())
    print(iterator.__next__())
    print(iterator.__next__())  # 迭代器返回值完毕后,程序报错“StopIteration”

    Iterable 可迭代的 -- > __iter__  只要含有__iter__方法的都是可迭代的
    [].__iter__() 迭代器 -- > __next__  通过next就可以从迭代器中一个一个的取值

    迭代器协议和可迭代协议

    • 可以被for循环的都是可迭代的
    • 可迭代的内部都有__iter__方法
    • 只要是迭代器,就一定可迭代
    • 可迭代的__iter__()可以得到一个迭代器
    • 迭代器中的__next__方法可以一个一个的获取值

    迭代器的好处

    • 从容器中可以一个一个的取值,能取到所有值
    • 节省空间
      •   迭代器不会因此在内存中开辟一大块空间,而是随着循环,每次通过next方法,生成一个值
    print(range(100000000000000))
    print(list(range(1000000000)))

    运行上述代码,可以看到,第一个迭代器的时候,很快就返回了结果  range(0, 100000000000000)

    第二段代码,机子跑死机了,都无法正常运行

    2、生成器函数

    含有yiled关键字的函数都是生成器函数

    #正常函数
    def generaor():
        print('1')
        return 'a'
    
    ret=generaor()
    print(ret)

    还有yiled关键字时,不能含有return关键字

    def generaor():
        print('1')
        yield 'a'  # 替换return关键字未yield关键字后,就是一个生成器
    
    ret=generaor()
    print(ret)

    def generaor():
        print('1')
        yield 'a'  # 替换return关键字未yield关键字后,就是一个生成器
    
    ret=generaor()
    print(ret)
    print("next get value:", ret.__next__())  # 生成器使用next函数获取值

     生成器中,使用双下线方法来获取返回值

    含有多个yield时,每次使用__next__都是到yield时,停止执行,返回值。

    单生成器中的值返回完毕时,报错StopIteration

    def generaor():
        print('1')
        yield 'a'  # 替换return关键字未yield关键字后,就是一个生成器
        print('2')
        yield 'b'
        yield 'c'
    
    ret=generaor()
    print(ret)
    print("next get value:", ret.__next__())  # 生成器使用next函数获取值
    # 1
    # next get value: a
    
    print("next get value:", ret.__next__())  # 生成器使用next函数获取值
    # 2
    # next get value: b
    
    print("next get value:", ret.__next__())  # 生成器使用next函数获取值
    # next get value: c
    #
    print("next get value:", ret.__next__())  # 生成器使用next函数获取值
    # 报错StopIteration,生成器到达最后的值报错

    同时定义多个生成器时,多个生成器间并不矛盾,每个都能获取各自独立的值

    def bear():
        for i in range(20000):
            yield "bear %s" % i
    
    g = bear()
    g2 = bear()
    
    print('生成器函数1:%s' % g.__next__())
    print('生成器函数1:%s' % g.__next__())
    print('生成器函数2:%s' % g2.__next__())
    print('生成器函数2:%s' % g2.__next__())
    print('生成器函数1:%s' % g.__next__())

    总结:

    迭代器:

    • 双下方法:很少直接调用的方法,一般情况下,通过其他语法触发;
    • 可迭代的:可迭代协议,含有__iter__方法('__iter__' in dir(类型))
    •   可迭代的一定可以被for循环;
    • 迭代器协议:含有__iter__和__next__的方法。
    •   迭代器一定可以迭代,可迭代的通过__iter__方法可以得到一个迭代器
    • 迭代器的特点:
    •   可以方便的遍历,且每个元素之使用一次;
    •   节省内存;

    生成器:

    生成器的本质是一个迭代器

    • 生成器函数:
    • 含有yield关键字的函数就是生成器:
    • 特点
      • 调用函数,并不会立即执行,返回一个生成器
      • 每次调用,使用__next__获取一个值
      • 直到取完最后一个值,报错

    从生成器中取数的几个方法:

    •   for
    •   __next__
    •   数据类型强制转换,暂用内存

    练习:

    def tail(filename):
        with open(filename) as f:
            while True:
                line = f.readline()
                line = line.strip()
                if line:
                    yield line
    
    res = tail('file')
    for line in res:
        if 'bear' in line:
            print('***', line)
    def generator():
        for i in range(2000000000):
            yield "hello, bear %s" % i
    
    g = generator()
    print(g.__next__())
    n = 0
    for content in g:
        n += 1
        if n > 50:
            break
        print(content)
  • 相关阅读:
    mysql leetcode 1445. 苹果和桔子 分组求差值
    前后端分离的理解
    mysql leetcode 178. 分数排名 自定义排名序号列 1,2,3
    mysql 距离今日,过去一年/一个月/一天 表达式
    mysql leetcode 1280. 学生们参加各科测试的次数 解题思路 一步一步来
    mysql leetcode 1435. 制作会话柱状图 解题思路 一步一步来
    leetcode 刷题笔记 寻找数组的中心索引 二分法查找
    mysql case when 理解和应用
    三角函数
    冒泡排序,选择排序,插入排序
  • 原文地址:https://www.cnblogs.com/zxw-xxcsl/p/11727546.html
Copyright © 2011-2022 走看看