Python高级功能实战详解---迭代器iterator

'''
需求:遍历一个一个班级的学生
传统方式会写一个显示函数,然后遍历
更好的方式是直接遍历该对象
'''
class ClassRoom(object):
    def __init__(self):
        self.students = []           #定义列表存储所有学生,初始为空

    def add_student(self, name, age, score):
        stu = {'name':name, 'age':age, 'score':score}
        self.students.append(stu)
    def show_student(self):
        for stu in self.students:
            print(f"name is : {stu['name']}")
            print('age is : {}'.format(stu['age']))
            print('score is : %d'%stu['score'])

clsrm = ClassRoom()
clsrm.add_student('hddd', 23, 344)
clsrm.add_student('aaadd', 13, 324)

#调用对象方法显示
clsrm.show_student()
#直接访问对象属性方式显示
for stu in clsrm.students:
    print(stu)

#如果直接使用下面方式是不是更好?
# for stu in clsrm:       #提示错误TypeError: 'ClassRoom' object is not iterable
#     print(stu)
#综上,提示clsrm是一个非迭代对象,那么,如果该对象可以迭代是不是就解决问题了?那怎么让对象成为可迭代对象呢?
#什么是可迭代对象?简单点就是说可以放到for循环里遍历读取数据,可以通过for循环反复的获取数据
#在原来的数据上能得到一个新的数据就叫迭代
#例如常见的可迭代对象string,list,tupple,set,dict...
for a in 'str'*3:
    print(a)
for b in [1,2,3,3]*2:
    print(b)
for c in {'dd':12, 'cc':123, 12:22}:  #字典不支持*复制
    print(c)
for d in {1,2,34,54,22}:  #集合不支持*复制
    print(d)
for e in (1, 2, 3, 4, 5)*3:
    print(e)
#检查对象是否可迭代方法
from collections.abc import Iterable
from collections.abc import Iterator

print(isinstance([], Iterable))
print(isinstance({}, Iterable))
print(isinstance('aaa', Iterable))
print(isinstance((1,2), Iterable))
print(isinstance((), Iterable))
print(type(()))     #<class 'tuple'>
print(type({}))     #<class 'dict'>

#迭代器定义:迭代器是一个可以记住遍历位置的对象,迭代器对象可以从第一个元素开始访问,直到所有的元素访问完结束。迭代器只能前不能退。
#比如遍历列表时,迭代器对象就是记录这个列表有多少个元素跟当前遍历到第几个元素位置的对象,该对象用来辅助遍历列表,那么该对象就是迭代器
#那么该列表就被称为可迭代对象,迭代器对象用来遍历该列表。
Nums = [11, 22, 33, 44, 55]  #定义一个列表
it = iter(Nums)   #通过iter方法可以获取列表的迭代器对象(iter方法可以获取可迭代对象的迭代器对象,所有可迭代对象必须定义__iter__()魔法方法)
print(type(it))  #<class 'list_iterator'>
#那么可以对通过iter()得到的迭代器进行迭代遍历了
print(next(it))     #对迭代器对象调用next,可以得到下一个值
# for 循环调用总结:
# 1:for循环先调用iter方法,对可迭代对象获取对应的迭代器,例如对Nums调用iter方法得到迭代器对象
# 2:对迭代器对象调用next方法,将上一步的迭代器取值
# 3:将上一步取出来的值赋值给it
# 4:执行循环体代码,指向print(it)
# 5:重复指向2,3,4步骤
for it in Nums:
    print(it)
#迭代器遍历到最后一个元素会抛出异常,for循环会自带异常处理
Data = ['a', 'b', 'c']
itr = iter(Data)
print(next(itr))   #输出a
print(next(itr))    #输出b
print(next(itr))   #输出c
# print(next(itr))   #StopIteration,数据已经遍历完了,如果再调用next就会出发异常

#方法一,采用while循环执行,自己捕获遍历完成异常
DataTest = ['1', '2', '3']
itr = iter(DataTest)
while True:
    try:
        print(next(itr))       #输出'1' '2' '3'
    except StopIteration as e:
        print('exception is {}'.format(e))     #输出‘exception is ’该异常没有名字
        break
#写法二,提前计算可迭代对象的大小,防止遍历完后继续调用next出异常
DataTest = ['1', '2', '3', '4']
itr = iter(DataTest)
l  = 0
while l < len(DataTest):
    print(next(itr))
    l += 1

#举例自定义迭代器
#自定义迭代器需要定义一个可迭代对象,同时要能得到一个迭代器对象
#__iter__()方法有两个功能:1,标识该对象为可迭代对象,2,该函数返回一个迭代器对象
#__next__()方法有两个功能:1,标识当前类创建的对象一定是迭代器(当然该类肯定必须还有__iter__()方法),2,当调用next函数的时候会调用该函数
#举例:可迭代对象与迭代器分开为两个类
class Zoom(object):                  #可迭代对象
    def __init__(self):
        self.animal=[]
        self.max = 0
    def __iter__(self):               #只要定义__iter__()方法,那么该类对象就是可迭代对象
        print('call zoom iter()')
        return ZoomIterator(self)
    def add_animal(self, animal):
        self.animal.append(animal)
        self.max += 1
    def get_animal(self, index):
        return self.animal[index]
    def get_max(self):
        return self.max

class ZoomIterator(object):               #迭代器对象
    def __init__(self, zoom):
        self.index = 0
        self.zoom = zoom
    # def __iter__(self):             #迭代器对象的iter函数主要是用于告诉迭代器也是可迭代对象,其实该函数可以不要
    #     print('call ZoomIterator iter()')          #该函数实际未调用
    #     return self
    def __next__(self):             #迭代器对象的遍历函数
        print('call ZoomIterator next()')
        if self.index < self.zoom.get_max():
            temp = self.zoom.get_animal(self.index)
            self.index += 1
            return temp
        else:
            raise StopIteration
zm = Zoom()
zm.add_animal('dog')
zm.add_animal('cat')
zm.add_animal('monkey')
zm.add_animal('tiger')
print('test -----Iterable/Iterator------Test')
print(isinstance(zm, Iterable))  #True
print(isinstance(zm, Iterator))  #False
print(isinstance(Zoom, Iterable))  #False
print(isinstance(ZoomIterator, Iterable))  #False
anim = ZoomIterator(zm)
print(isinstance(anim, Iterable))  #False,没有iter函数所以不是可迭代对象
print(isinstance(anim, Iterator))  #False ,因为把iter函数注释掉了,所以就不是迭代器了,实际上也是可以迭代出数据的
for ani in zm:
    print(ani)          #正确遍历出元素


#举例:可迭代对象与迭代器合二为一,只有一个类
class ZoomAnimal(object):              #可迭代对象与迭代器放在一个类里实现
    def __init__(self):
        self.animal = []
        self.max = 0
        self.index = 0
    def __iter__(self):         #定义该函数那么就是可迭代对象
        print('call ZoomAnimal iter()')
        self.index = 0           #多次迭代从头开始,否则只能迭代遍历一次
        return self
    def __next__(self):         #迭代器对象的遍历函数
        print('call ZoomAnimal next()')
        if self.index < self.max:
            temp = self.animal[self.index]
            self.index += 1
            return temp
        else:
            raise StopIteration
    def add_animal(self, animal):
        self.animal.append(animal)
        self.max += 1
zmani = ZoomAnimal()
print(isinstance(zmani, Iterable))  #True
zmani.add_animal('dog')
zmani.add_animal('cat')
zmani.add_animal('monkey')
zmani.add_animal('tiger')
print('zmani output')
for zn in zmani:
    print(zn)
print('zmani output 2')
for zn in zmani:
    print(zn)

#可迭代对象可以当作原始数据生产list,set等,通过可迭代对象生成list
print('genarate list from iterable object')
num = list(zmani)
# num =[x for x in zmani] #等价于num = list(zmani)
print(num)

#总结:调用iter(instance)方法,实际会调用instance.__iter__()方法,
# 调用next(instance)方法,实际会调用instance.__next__()方法
#如果可迭代对象与迭代器对象分开两个类定义,迭代器对象的iter方法是不会被调用到,但是python定义的迭代器对象必须是可迭代对象
#所以分开定义的时候迭代器中一定要定义iter方法,该方法中直接返回self就可以
#因此可迭代对象不一定是迭代器,但是迭代器一定是可迭代对象
#可迭代对象:定义了iter方法,迭代器对象:定义了iter方法且定义了next方法
#迭代器调用流程是:
#第一步:先通过iter()方法产生一个迭代器对象
#第二步:通过第一步产生的迭代器对象,每调用一次next()方法得到一个遍历出来的元素
#第三步:当所有元素遍历完再调用next()方法的话会抛出StopIteration异常
#标准可迭代对象定义如下:
class Mylsit(object):
    def __iter__(self):           #可迭代对象
        pass
class MyListIterator(object):
    def __iter__(self):         #可迭代对象
        pass
    def __next__(self):         #迭代器
        pass

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值