• python基础篇_005_迭代器和生成器


    Python迭代器和生成器

    1.迭代器

    迭代:可以将某个数据集内的数据“一个挨着一个的取出来”

    for i in range(1, 10, 2):  # in 后面的对象必须是一个可迭代的
        print(i)  # 从可迭代对象中将元素一个一个取出
    """
    判断是否可迭代
    """
    from collections import Iterable
    
    str1 = 'adc'
    l = [1, 2, 3, 4]
    t = (1, 2, 3, 4)
    d = {1: 2, 3: 4}
    s = {1, 2, 3, 4}
    print(isinstance(str1, Iterable))
    print(isinstance(l, Iterable))
    print(isinstance(t, Iterable))
    print(isinstance(d, Iterable))
    print(isinstance(s, Iterable))  # True
    
    int1 = 1234
    print(isinstance(int1, Iterable))  # False

    2.可迭代协议

    可以被迭代要满足的要求就叫做可迭代协议。内部实现了__iter__方法。

    print(dir(str))  # 可迭代,内部要有一个__iter__()方法
    print(str1.__iter__())
    #['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    #<str_iterator object at 0x0000000000A6DB38>
    str_iterator

    iterator 就是迭代器
    str1 = 'abc'
    dir(str1)  # 列出所有字符串实现的方法
    set1 = set(dir(str1))
    set2 = set(dir(str1.__iter__()))
    print(set2 - set1)
    #  {'__length_hint__', '__next__', '__setstate__'}

    迭代器多了三个方法

    """迭代器中的方法作用"""
    str1 = 'abc'
    # 获取迭代器
    iter_1 = str1.__iter__()
    # 获取迭代器中元素的长度
    print(iter_1.__length_hint__())  # 3
    # 根据索引值指定从哪里开始迭代
    print(iter_1.__setstate__(1))  # None
    # 一个一个的取值
    print(iter_1.__next__())     # b  for 循环内部调用 实现一个一个取值

    自己实现迭代取数:

    str1 = 'abc'
    # 获取迭代器
    iter1 = str1.__iter__()
    
    # 循环取出
    while 1 :
        a = iter1.__next__()
        print(a)
    # a
    # b
    # c
    # 
    # Traceback (most recent call last):
    #   File "E:/Python/d01/函数.py", line 8, in <module>
    #     a = iter1.__next__()
    # StopIteration

    异常机制处理异常:

    str1 = 'abc'
    # 获取迭代器
    iter1 = str1.__iter__()
    
    # 循环取出
    while 1:
        try:
            a = iter1.__next__()
            print(a)
        except StopIteration:
            break
    # a
    # b
    # c

    3.生成器

    实现迭代器功能的东西就是生成器

    Python中提供的生成器:
    
    1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行
    
    2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
    
    生成器Generator:
    
      本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
    
      特点:惰性运算,开发者自定义

    生成器函数

    1.生成器函数:一个包含yield关键字的函数就是一个生成器函数。
    2.yield与reduce区别:
      yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,
      而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
    def genrator_f1():
        a = 1
        print('a变量')
        yield a
        b = 2
        print('b变量')
        yield b
    
    
    g1 = genrator_f1()    #  g1获取的是生成器
    print(g1.__next__())  
    print(g1.__next__())
    print(g1.__next__())
    
    # a变量
    # 1
    # b变量
    # 2
    # Traceback (most recent call last):
    #   File "E:/Python/d01/test.py", line 14, in <module>
    #     print(g1.__next__())
    # StopIteration

    生成器的优点:不会在内存中瞬间生成很多数据

    def produce():
        for i in range(10):
            yield "生产序列号:%d" % i
    
    
    # 获取生成器
    pro_g = produce()
    print(pro_g.__next__())   # 一个一个获取
    print(pro_g.__next__())
    print(pro_g.__next__())
    
    num = 0             # 批量获取
    for i in pro_g:
        print(i)
        num += 1
        if num == 5:
            break
    # 生产序列号:0
    # 生产序列号:1
    # 生产序列号:2
    # 生产序列号:3
    # 生产序列号:4
    # 生产序列号:5
    # 生产序列号:6
    # 生产序列号:7

    实现日志实时监控: Linux tail -f 

    import time
    
    
    def tail(filename):
        with open(filename,mode='r',encoding='utf-8') as f:
            f.seek(0, 2)  # 从文件末尾算起
            while True:
                line = f.readline()  # 读取文件中新的文本行
                if not line:
                    time.sleep(1)
                    continue
                yield line
    
    
    tail_g = tail('C:\Users\18047463\Desktop\test.txt')
    for line in tail_g:
        print(line.strip())

    实时计算平均数:

    def averager():
        total = 0.0
        count = 0
        average = None
        while 1:
            term = yield average
            total += term
            count += 1
            average = total / count
    
    
    g_avg = averager()
    g_avg.__next__()  # 初始化
    while 1:
        num = input(">>>")
        if num == 'q':
            break
        print(g_avg.send(int(num)))

    初始化使用装饰器:

    from functools import wraps
    
    
    def init(func):
        @wraps(func)
        def inner(*args, **kwargs):
            g = func(*args, **kwargs)
            g.__next__()
            return g
    
        return inner
    
    
    @init
    def averager():
        total = 0.0
        count = 0
        average = None
        while 1:
            term = yield average
            total += term
            count += 1
            average = total / count
    
    
    g_avg = averager()
    while 1:
        num = input(">>>")
        if num == 'q':
            break
        print(g_avg.send(int(num)))
    def gen1():
        for c in 'AB':
            yield c
        for i in range(3):
            yield i
    
    
    print(list(gen1()))
    
    
    def gen2():
        yield from 'AB'
        yield from range(3)
    
    
    print(list(gen2()))

    列表推导式和生成器表达式

    egg_list=['鸡蛋%s' %i for i in range(10)]  #列表解析
    print(egg_list)
    # ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
    laomuji=('鸡蛋%s' %i for i in range(10))  #生成器表达式  相比列表解析,更加节省内存
    print(laomuji)  # <generator object <genexpr> at 0x00000000013F8780>
    print(next(laomuji)) #next本质就是调用__next__
    print(laomuji.__next__())
    print(next(laomuji))
  • 相关阅读:
    Python 抓取 iphone13 pro 线下店供货信息并发送到钉钉机器人,最后设置为定时任务
    crontab 解决 mac 下通过 crontab 设置了 Python 脚本的定时任务却无法运行
    Python 好用第三方库 isort
    Python 接入钉钉机器人
    Effective Python(2) 遵循 PEP 8 风格指南
    fastapi(65) 路由函数指定了 response_model,在返回自定义 JSONResponse 时, 不会限制它返回的数据结构
    Mysql 如何决定用 datetime、timestamp、int 哪种类型存储时间戳?
    Effective Python(1) 查询自己使用的Python版本
    fastapi(66) 修改 uvicorn 的日志格式
    重要通知!重要通知!不是广告!不是广告!
  • 原文地址:https://www.cnblogs.com/yin-fei/p/10763702.html
Copyright © 2020-2023  润新知