python里for遍历执行流程及自定义可迭代器对象和迭代器

    技术2022-08-31  71

    一、简单的模拟for执行过程

    执行过程:

    for temp in xxx_obj: pass 1.先判断xxx_obj是否可以迭代的对象; 2.如果xxx_obj是可迭代的,自动调用iter函数,iter函数自动调用xxx_obj对象的__iter__方法; 3.如果xxx_obj对象的__iter__方法的返回值是一个迭代器,之后for通过自动调用next函数来间接调用迭代器里的__next__函数来取出数据.

    模拟的代码如下:用两个类模拟,一个是创建可迭代对象的类,一个是创建迭代器的类。

    from collections.abc import Iterable, Iterator # 迭代器类 class ClassIterator(object): def __init__(self): pass def __iter__(self): pass def __next__(self): """同时有__iter__和__next__的类创建的对象是一个迭代器""" return "nice" # 可迭代对象类 class Classmate(object): def __init__(self): self.names = list() def add(self, name): self.names.append(name) def __iter__(self): """只要添加__iter__方法,该类创建的对象就是可以迭代的对象""" return ClassIterator() # 返回一个迭代器 def main(): classmate = Classmate() # 模拟for执行 # 1. 判断是否是可迭代的对象 print("classmate是否是可以迭代的对象:", isinstance(classmate, Iterable)) # 2.iter调用可迭代对象的__iter__,并返回一个迭代器 if isinstance(classmate, Iterable): # iter会调用实参classmate的__iter__,返回一个迭代器 classmate_iterator = iter(classmate) print("classmate_iterator是否是迭代器:", isinstance(classmate_iterator, Iterator)) # 3.next调用迭代器的__next__,返回数据 if isinstance(classmate_iterator, Iterator): # next会调用实参classmate_iterator的__next__ print(next(classmate_iterator)) if __name__ == "__main__": main()

    代码执行结果:

    classmate是否是可以迭代的对象: True classmate_iterator是否是迭代器: True nice

    二、自定义可迭代的类:在类里实现__iter__和__next__方法

    from collections.abc import Iterable, Iterator class Classmate(object): def __init__(self): self.names = list() # 存储要遍历的数据 self.current_num = 0 # 下标,记录当前遍历的位置 def add(self, name): self.names.append(name) def __iter__(self): return self # 自身就是迭代器,所以返回self自己,返回谁下一步就调用谁的__next__ def __next__(self): # 只要容器里的数据没有被取完,for就一直调用__next__ if self.current_num < len(self.names): ret = self.names[self.current_num] self.current_num += 1 return ret else: raise StopIteration # 遍历结束(取完数据),抛出停止遍历的异常 def main(): # 自定义类创建可迭代的对象 classmate = Classmate() classmate.add(10) classmate.add(20) classmate.add(30) # 遍历自定义类创建的对象 for temp in classmate: print(temp) if __name__ == "__main__": main()

    注:如果上面的代码不好理解,可以先看下面的代码

    from collections.abc import Iterable, Iterator # 迭代器类 class ClassIterator(object): def __init__(self, another_obj): # 将要遍历的对象赋值给迭代器的self.obj self.obj = another_obj # 存储待遍历的对象 self.current_num = 0 # 下标,记录当前遍历到哪个元素 def __iter__(self): pass def __next__(self): """同时有__iter__和__next__的类创建的对象是一个迭代器""" if self.current_num < len(self.obj.names): ret = self.obj.names[self.current_num] self.current_num += 1 return ret else: raise StopIteration # 抛出异常,遍历结束 # 可迭代对象类 class Classmate(object): def __init__(self): self.names = list() def add(self, name): self.names.append(name) def __iter__(self): """只要添加__iter__方法,该类创建的对象就是可以迭代的对象""" return ClassIterator(self) # 创建返回一个迭代器,要遍历self,所以要传递self def main(): classmate = Classmate() classmate.add(10) classmate.add(20) classmate.add(30) for temp in classmate: print(temp) if __name__ == "__main__": main()

    三、使用迭代器节约内存空间

      迭代器作用:使用迭代器,可以不用预先知道要分配多大的空间,当数据规模比较大时,如果使用列表、元组等来存储数据,需要开辟很大的内存空间。而使用迭代器可以不用分配这么大的空间,迭代器是在不断迭代遍历的时候生成数据。迭代器不存储要遍历的数据,而是存储产生该数据的方式。一般用于遍历有规律的数据。   例子:遍历斐波那契数列

    class Fibonacci(object): def __init__(self, all_num): self.all_num = all_num # 要创建多少个数 self.current_num = 0 # 当前已经创建的个数 self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): """只要不抛出异常,for就会一直调用__next__""" if self.current_num < self.all_num: ret = self.a self.a, self.b = self.b, self.a+self.b self.current_num += 1 return ret else: raise StopIteration if __name__ == "__main__": all_cnt = 8 fib = Fibonacci(all_cnt) cnt = 1 for num in fib: # 将__next__返回的结果赋值给num if cnt < all_cnt: print(num, end=",") else: print(num) cnt += 1

    结果:

    0,1,1,2,3,5,8,13
    Processed: 0.011, SQL: 9