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)

  

 

posted @ 2019-04-22 18:51  一如年少模样  阅读(253)  评论(0编辑  收藏  举报