• Python基础之迭代器、生成器


    一、迭代器:

      1、迭代:每一次对过程的重复称为一次迭代,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。

      2、可迭代对象(iterable):

        1)定义:具有__iter__函数的对象,可以返回迭代器对象

        2)语法:  

          

        3)原理:

          

      

      3、迭代器对象(iterator):

        1)定义:可以被next()函数调用并返回下一个值的对象

        2)语法:

        

        3)说明及作用:

          

    二、生成器(generator):

      

    三、生成器函数:

      

       6、内置生成器:

        

      7、生成器表达式:

        

    四、基础代码:

      代码1:

      

    """
        可迭代对象:具有__iter__()方法,可以返回迭代器的对象.
    """
    list01 = [2,434,5,6,8]
    
    # for item in list01:
    #     print(item)
    
    # 面试题:
    # 能够被for循环的条件是:可迭代对象(具有__iter__()方法的对象)
    
    # for循环原理
    # 1. 获取迭代器对象
    # 2. 循环迭代(调用迭代器的__next__方法)
    # 3. 捕获StopIteration异常
    
    #1.
    # iterator = list01.__iter__()
    #2.
    # item = iterator.__next__()
    # print(item)
    #
    # item = iterator.__next__()
    # print(item)
    #
    # item = iterator.__next__()
    # print(item)
    #
    # item = iterator.__next__()
    # print(item)
    #
    # item = iterator.__next__() # 最后一次
    # print(item)
    # 3.
    # item = iterator.__next__()# StopIteration
    # print(item)
    
    # 1. 获取迭代器对象
    iterator = list01.__iter__()
    while True:
        try:# 如果获取了全部元素,则执行except
            # 2. 获取下一个元素(迭代过程)
            item = iterator.__next__()
            print(item)
            # 3.停止迭代(StopIteration 错误)
        except StopIteration:
            break # 跳出循环体

      代码2:

      

    """
        迭代器
    """
    
    
    class Skill:
        pass
    
    
    class SkillIterator:
        """
            技能迭代器
        """
        def __init__(self, target):
            self.target = target
            self.index = 0
    
        def __next__(self):
    
            # 如果索引越界 则抛出异常
            if self.index > len(self.target) - 1:
                raise StopIteration()
            # 返回下一个元素
            item = self.target[self.index]
            self.index += 1
            return item
    
    
    class SkillManager:
        """
            可迭代对象
        """
        def __init__(self, skills):
            self.skills = skills
    
        def __iter__(self):
            # 创建迭代器对象  传递 需要迭代的数据
            return SkillIterator(self.skills)
    
    
    #---------------以下是客户端代码---------------------
    
    manager = SkillManager([Skill(), Skill(), Skill()])
    # for item in manager.skills:
    for item in manager:# 获取manager对象中列表元素(获取manager对象的聚合类型对象元素)
        print(item)
    # iterator = manager.__iter__()
    # while True:
    #     try:
    #         item = iterator.__next__()
    #         print(item)
    #     except:
    #         break

      代码3:

      

    """
        迭代器 --> yield
    
    """
    
    class Skill:
        pass
    
    
    # class SkillIterator:
    #     """
    #         技能迭代器
    #     """
    #     def __init__(self, target):
    #         self.target = target
    #         self.index = 0
    #
    #     def __next__(self):
    #         if self.index > len(self.target) - 1:
    #             raise StopIteration()
    #         item = self.target[self.index]
    #         self.index += 1
    #         return item
    
    
    class SkillManager:
        def __init__(self, skills):
            self.skills = skills
    
        # def __iter__(self):
        #     return SkillIterator(self.skills)
    
        def __iter__(self):
            """
                执行过程:
                1.调用__iter__()方法不执行
                2.调用__next__()方法时执行,到yield语句暂时离开.
                3.再次调用__next__()方法时,从上次离开的代码开始执行,到yield语句暂时离开
                4. 待执行完方法体,抛出StopIteration异常.
    
                原理:如果方法体中包含yield关键字,那么会自动生成迭代器对象.
                生成迭代器代码的大致规则: 
                1. 将yield关键字以前的代码,放到__next__方法中.
                2. 将yield关键字以后的数据,作为__next__方法的返回值
            """
            # print("准备返回第一个元素")
            # yield self.skills[0]  # 暂时离开点   再次执行点
            #
            # print("准备返回第二个元素")
            # yield self.skills[1]
            #
            # print("准备返回第三个元素")
            # yield self.skills[2]
    
            for item in self.skills:
                yield item
    
    
    
    #---------------以下是客户端代码---------------------
    
    manager = SkillManager([Skill(), Skill(), Skill()])
    
    # for item in manager:
    #     print(item)
    
    iterator = manager.__iter__()
    while True:
        try:
            item = iterator.__next__()
            print(item)
        except Exception as e:
            print(e)
            break

      代码4:

      

    """
        yield -->  生成器函数
    """
    
    # class MyRange:
    #     def __init__(self, stop):
    #         self.stop = stop
    #
    #     def __iter__(self):
    #         start = 0
    #         while start < self.stop:
    #             yield start
    #             start += 1
    #
    # for item in MyRange(5):
    #     print(item)
    
    
    # 生成器函数
    def my_range(stop):
        start = 0
        while start < stop:
            yield start
            start += 1
    
    # for item in my_range(5):
    #     print(item)
    
    iter01 = my_range(5)
    for item in iter01:
         print(item)

      代码5:

      

    """
        内置生成器:enumerate
    """
    
    list01 = ["a", "b", "c"]
    
    for item in enumerate(list01):
        # (索引,元素)
        print(item)
    
    for index, element in enumerate(list01):
        print(index, element)
    
    # 练习:参照上述代码,自定义函数,my_enumerate.
    # 10:46
    
    def my_enumerate(target):
        index = 0
        for item in target:
            yield (index,item)
            index += 1
    
    for item in my_enumerate(list01):
        print(item)
    
    for index, element in my_enumerate(list01):
        print(index, element)

      代码6:

      

    """
        内置生成器:zip
    """
    
    list02 = [101,102,103]
    list03 = ["张三丰","张无忌","赵敏"]
    for item in zip(list02,list03):
        # (101, '张三丰')
        print(item)
    
    #练习:参照上述代码,自定义函数,my_zip  11:05
    def my_zip(list01,list02):
        for index in range(len(list01)):
            # yield (list01[index],list02[index])
            yield list01[index], list02[index]
    
    for item in my_zip(list02,list03):
        # (101, '张三丰')
        print(item)

      代码7:

      

    """
        生成器表达式
    """
    
    list01 = [2,3,4,6]
    # result = []
    # for item in list01:
    #     result.append(item ** 2)
    
    # 列表推导式[]     字典推导式 {键:值 for ...}   集合 { for ... }
    result = [item ** 2 for item in list01]
    print(result)
    
    # def fun01(target):
    #     for item in target:
    #         yield item ** 2
    # 生成表达式
    # for item in fun01(list01):
    #     print(item)
    
    result = (item ** 2 for item in list01)
    for item in result:
        print(item)

    五、练习实例:

      练习1:

      

    # 练习1:("悟空","八戒","沙僧","唐僧")
    # 使用while + 迭代器 获取元组所有元素
    t01 = ("悟空", "八戒", "沙僧", "唐僧")
    iterator = t01.__iter__()
    while True:
        try:
            item = iterator.__next__()
            print(item)
        except:
            break
    
    # 练习2:{"张三丰":101,"张无忌":102,"赵敏":102}
    # 不使用for循环,获取字典所有元素.
    
    d01 = {"张三丰": 101, "张无忌": 102, "赵敏": 102}
    iterator = d01.__iter__()
    while True:
        try:
            key = iterator.__next__()
            print(key, d01[key])
        except:
            break

      练习2:

      

    """
        练习:迭代员工管理器对象
        
    """
    
    
    class Employee:
        pass
    
    
    class EmployeeIterator:
        """
            迭代器
        """
        def __init__(self, target):
            self.target = target
            self.index = 0
    
        def __next__(self):
            if self.index > len(self.target) - 1:
                raise StopIteration()
            item = self.target[self.index]
            self.index += 1
            return item
    
    
    # 可迭代对象
    class EmployeeManager:
        def __init__(self, employees):
            self.all_employee = employees
    
        def __iter__(self):
            # 返回迭代器
            return EmployeeIterator(self.all_employee)
    
    
    manager = EmployeeManager([Employee(), Employee()])
    
    # 需求:for循环自定义类的对象
    # for item in manager:
    #     print(item)  #
    
    iterator = manager.__iter__()
    while True:
        try:
            item = iterator.__next__()
            print(item)
        except:
            break

      练习3:

        

    """
        参照下列代码,定义MyRange类,实现相同效果.
        
    """
    
    # 15:40
    class MyRangeIterator:
        def __init__(self, stop):
            self.stop = stop
            self.start = 0
    
        def __next__(self):
            if self.start + 1 > self.stop:
                raise StopIteration()
            temp = self.start
            self.start += 1
            return temp
    
    
    class MyRange:
        def __init__(self, stop):
            self.stop = stop
    
        def __iter__(self):
            # 创建迭代器对象
            return MyRangeIterator(self.stop)
    
    
    # for item in range(5):
    #     print(item)#
    
    # for item in MyRange(5):
    #     print(item)#0 1 2 3 4
    
    iterator = MyRange(5)
    for item in iterator:
        print(item)  #
    
    # iterator = iterator.__iter__()
    # while True:
    #     try:
    #         item = iterator.__next__()
    #         print(item)
    #     except:
    #         break

      练习4:

        

    """
         改造为yield实现
    """
    
    
    class Employee:
        pass
    
    
    # class EmployeeIterator:
    #     """
    #         迭代器
    #     """
    #     def __init__(self, target):
    #         self.target = target
    #         self.index = 0
    #
    #     def __next__(self):
    #         if self.index > len(self.target) - 1:
    #             raise StopIteration()
    #         item = self.target[self.index]
    #         self.index += 1
    #         return item
    
    
    # 可迭代对象
    class EmployeeManager:
        def __init__(self, employees):
            self.all_employee = employees
    
        # def __iter__(self):
        #     # 返回迭代器
        #     return EmployeeIterator(self.all_employee)
    
        def __iter__(self):
            for item in self.all_employee:
                yield item
    
    
    manager = EmployeeManager([Employee(), Employee()])
    
    # 需求:for循环自定义类的对象
    # for item in manager:
    #     print(item)  #
    
    iterator = manager.__iter__()
    while True:
        try:
            item = iterator.__next__()
            print(item)
        except:
            break

      练习5:

      

    """
         改造为yield实现
    """
    
    
    # class MyRangeIterator:
    #     def __init__(self, stop):
    #         self.stop = stop
    #         self.start = 0
    #
    #     def __next__(self):
    #         if self.start + 1 > self.stop:
    #             raise StopIteration()
    #         temp = self.start
    #         self.start += 1
    #         return temp
    
    
    class MyRange:
        def __init__(self, stop):
            self.stop = stop
    
        # def __iter__(self):
        #     # 创建迭代器对象
        #     return MyRangeIterator(self.stop)
    
        def __iter__(self):
            start = 0
            while start < self.stop:
                yield start
                start += 1
    
    
    iterator = MyRange(5)
    # for item in iterator:
    #     print(item)  #
    
    iterator = iterator.__iter__()
    while True:
        try:
            item = iterator.__next__()
            print(item)
        except:
            break

      练习6:

      

    """
        生成器函数练习
        体会:方法/函数,需要向外返回多个结果时,使用生成器函数.
             惰性操作/延迟操作 (生成器函数的"循环(next)一次,计算一次,返回一次")
    
    """
    list01 = [23,3,4,556,677,68,8,98,98]
    # 练习1:在list01中,挑出所有偶数.
    # 要求:1)使用生成器函数实现
    def get_even01(target):
        for item in target:
            if item % 2 == 0:
                yield item
    
    iter01 = get_even01(list01)# 没有执行方法体
    for item in iter01:# 循环(next)一次,计算一次,返回一次
        print(item)
    
    # def get_even02(target):
    #     result = []
    #     for item in target:
    #         if item % 2 == 0:
    #             result.append(item)
    #     return result
    #
    # iter01 = get_even02(list01)# 执行方法体,将所有结果存在内存中.
    # for item in iter01:
    #     print(item)
    
    # 练习2:定义函数,选出所有女同学.
    class Student:
        def __init__(self,name,sex,age,score):
            self.name = name
            self.sex = sex
            self.age = age
            self.score = score
    
        def __str__(self):
            return "%s--%s--%d--%d"%(self.name,self.sex,self.age,self.score)
    
    list_stu = [
        Student("张无忌","",28,82),
        Student("赵敏","",25,95),
        Student("周芷若","",26,88),
    ]
    
    def find_woman(target):
        for item in target:
            if item.sex == "":
                yield item
    
    for item in find_woman(list_stu):
        print(item)
    
    # 练习3:选出所有成绩大于90的学生
    def find_by_score(target):
        for item in target:
            if item.score > 90:
                yield item
    
    for item in find_by_score(list_stu):
        print(item)

      练习7:

      

    # 1.创建技能类(编号,技能名称,冷却时间,攻击力,消耗法力)
    #   创建技能列表.
    #   -- 定义函数:查找编号是101的技能对象
    #   -- 定义函数:查找冷却时间为0的所有技能对象
    #   -- 定义函数:查找攻击力大于5的所有技能对象
    #   -- 定义函数:查找攻击力大于10,并且不需要消耗法力的所有技能.
    
    class SkillData:
        def __init__(self, id, name, cd, atk, costSP):
            self.id = id
            self.name = name
            self.cd = cd
            self.atk = atk
            self.costSP = costSP
    
    
    list_skills = [
        SkillData(101, "降龙十八掌", 60, 10, 5),
        SkillData(102, "如来神掌", 50, 15, 0),
        SkillData(103, "六脉神剑", 0, 20, 8),
        SkillData(104, "一阳指", 0, 50, 15),
        SkillData(105, "冷酷追击", 15, 30, 9),
    ]
    
    
    # 因为需要查找的结果只有一个,所以使用return返回数据.
    # 比使用yield返回数据,在调用者看来,更加方便吧.
    def find_demo01(target):
        for item in target:
            if item.id == 101:
                return item
    
    s01 = find_demo01(list_skills)
    print(s01.id)
    
    
    def find_demo02(target):
        for item in target:
            if item.cd == 0:
                yield item
    
    result = find_demo02(list_skills)
    # 不能获取指定结果
    # 因为:此时生成器函数并没有计算处结果.
    # print(result[1].name)
    # for item in result:
    #     print(item.name)
    
    
    result = find_demo02(list_skills)
    # 通过生成器创建列表
    # 由惰性查找(优势:节省内存) 转换为 立即查找(优势:灵活获取结果)
    result = list(result)
    # print(result[1].name)
    
    
    def find_demo03(target):
        for item in target:
            if item.atk > 5:
                yield item
    
    # 调用生成器函数,创建迭代器对象
    result = find_demo03(list_skills)
    for item in result:# __next__()
        print(item.name)
    
    print("---------------")
    # 如果没有下一行代码,再次for使用过的生成器对象,不会再有结果.
    # result = find_demo03(list_skills)
    for item in result:
        print(item.name)
    
    # for item in find_demo03(list_skills):
        # ....
    
    
    def find_demo04(target):
        for item in target:
            if item.atk > 10 and item.costSP == 0:
                yield item
    
    for item in find_demo04(list_skills):
        print(item.name)

      练习8:

      

    list02 = [2,3,4,6]
    # 练习:使用列表推导式,与生成器表达式,获取list02中,大于3的数据.
    
    result01 = [item for item in list02 if item > 3 ] # 本行代码:执行所有操作,保存所有结果
    result02 = (item for item in list02 if item > 3 ) # 本行代码:返回生成器对象
    
    for item in result01:# 从结果中获取数据
        print(item)
    
    for item in result02:# 循环一次,计算一次,返回一次
        print(item)

      练习9:

      

    # 1.创建技能类(编号,技能名称,冷却时间,攻击力,消耗法力)
    #   创建技能列表. 
    #   -- 定义函数:查找冷却时间为0的所有技能对象
    #   -- 定义函数:查找攻击力大于5的所有技能对象
    #   -- 定义函数:查找攻击力大于10,并且不需要消耗法力的所有技能.
    #   使用列表推导式,与生成器表达式完成
    #   通过断点调试,审查程序执行过程,体会两项技术的差异.
    
    
    class SkillData:
        def __init__(self, id, name, cd, atk, costSP):
            self.id = id
            self.name = name
            self.cd = cd
            self.atk = atk
            self.costSP = costSP
    
        def __str__(self):
            return self.name
    
    list_skills = [
        SkillData(101, "降龙十八掌", 60, 10, 5),
        SkillData(102, "如来神掌", 50, 15, 0),
        SkillData(103, "六脉神剑", 0, 20, 8),
        SkillData(104, "一阳指", 0, 50, 15),
        SkillData(105, "冷酷追击", 15, 30, 9),
    ]
    
    
    # def find_demo02(target):
    #     for item in target:
    #         if item.cd == 0:
    #             yield item
    
    result01 = (item for item in list_skills if item.cd == 0)
    result02 = [item for item in list_skills if item.cd == 0]
    
    for item in result01:
        print(item)
    
    for item in result02:
        print(item)
    
    # def find_demo03(target):
    #     for item in target:
    #         if item.atk > 5:
    #             yield item
    
    result01 = (item for item in list_skills if item.atk > 5)
    result02 = [item for item in list_skills if item.atk > 5]
    
    for item in result01:
        print(item)
    
    for item in result02:
        print(item)
    
    # def find_demo04(target):
    #     for item in target:
    #         if item.atk > 10 and item.costSP == 0:
    #             yield item
    result01 = (item for item in list_skills if item.atk > 10 and item.costSP == 0)
    result02 = [item for item in list_skills if item.atk > 10 and item.costSP == 0]
    
    for item in result01:
        print(item)
    
    for item in result02:
        print(item)

      

  • 相关阅读:
    google的开源项目总结
    Google Breakpad 完全解析(二) —— Windows前台实现篇
    Google Breakpad 完全解析(一) —— Windows入门篇
    PVS-Studio静态通用分析规则
    C,C++开源项目中的100个Bugs
    一日一点RakNet(3)--介绍
    C++开源跨平台类库集
    如何实现数组的随机排序?
    JavaScript原型,原型链 ? 有什么特点?
    js的基本数据类型
  • 原文地址:https://www.cnblogs.com/yuxiangyang/p/10752076.html
Copyright © 2020-2023  润新知