迭代
重复获取下一个元素的过程,例如:循环获取容器中的元素
for原理:
1.获取迭代器
1
| iterator = message.__iter__()
|
2.获取下一个元素
1 2 3 4 5 6 7
| while True: try: item = iterator.__next__() print(item) except StopIteration: break
|
可迭代对象(iterable)
可以创建迭代器的对象,具有iter函数的对象,可以返回迭代器对象,例如列表,元组等容器
迭代器(iterator)
执行迭代过程的对象,可以被next()函数调用并返回下一个值的对象,例如for循环
案例:自定义迭代器的创建
分析1:
创建一个学生管理类
1 2 3 4 5 6 7
| class StudentController:
def __init__(self): self.__students = []
def add_student(self, stu): self.__students.append(stu)
|
创建一个学生管理类的对象,并添加学生
1 2 3 4
| controller = StudentController() controller.add_student("张三") controller.add_student("李四") controller.add_student("王五")
|
如何遍历controller,若使用for循环,则会报错,因为’StudentController’ object is not iterable
1 2
| for item in controller: print(item)
|
分析2:为解决上述StudentController类不可迭代的问题,由文章开头for原理可知,要想可迭代需要具有iter函数,因此修改StudentController类,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class StudentController:
def __init__(self): self.__students = []
def add_student(self, stu): self.__students.append(stu)
def __iter__(self): pass
controller = StudentController() controller.add_student("张三") controller.add_student("李四") controller.add_student("王五")
for item in controller: print(item)
|
上述代码报错,iter() returned non-iterator of type ‘NoneType’
分析3:由文章开头原理可知,iter函数应当返回一个迭代器对象。因此创建另外一个类StudentIterator:即学生迭代器;学生迭代器应当有next函数,且调用next方法时,应当返回下一个元素,当取完所有元素后,发起异常,结束迭代。学生迭代器的要获取的元素应当由可迭代对象给予。因此修改代码如下:完成要求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class StudentController:
def __init__(self): self.__students = []
def add_student(self, stu): self.__students.append(stu)
def __iter__(self): return StudentIterator(self.__students)
class StudentIterator: def __init__(self, data): self.__data = data self.__index = -1
def __next__(self): if self.__index == len(self.__data) - 1: raise StopIteration() self.__index += 1 return self.__data[self.__index]
controller = StudentController() controller.add_student("张三") controller.add_student("李四") controller.add_student("王五")
for item in controller: print(item)
|
可迭代对象与迭代器为何分成两个类
因为多个可迭代对象可以使用同一个迭代器
生成器
前言
生成器:能够动态(循环一次计算一次返回一次)提供数据的可迭代对象
作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。
生成器函数=可迭代对象+迭代器
生成器函数定义:含有yield语句的函数,返回值为生成器对象
执行过程:
(1) 调用生成器函数会自动创建迭代器对象。
(2) 调用迭代器对象的next()方法时才执行生成器函数。
(3) 每次执行到yield语句时返回数据,暂时离开。
(4) 待下次调用next()方法时继续从离开处继续执行。
引例
创建自定义Myrange类1.0版本
实现以下功能
1 2
| for number in Myrange(5): print(number)
|
代码如下,使用自定义迭代器实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class MyrangeIterator: def __init__(self, target=None): self.__target = target self.__index = -1
def __next__(self): self.__index += 1 if self.__index == self.__target: raise StopIteration() return self.__index
class Myrange: def __init__(self, num=None): self.__num = num
def __iter__(self): return MyrangeIterator(self.__num)
for number in Myrange(5): print(number)
|
生成器函数yield
生成代码的大致规则:
1. 将yield关键字前面的代码作为__next__函数体
2. 将yield关键字后面的数据作为__next__返回值
创建自定义Myrange类2.0版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Myrange: def __init__(self, num=None): self.__num = num
def __iter__(self): number = 0 yield number number += 1 yield number number += 1 yield number
mr = Myrange(3) iterator = mr.__iter__() while True: try: item = iterator.__next__() print(item) except StopIteration: break
|
分析:iterator = mr.iter()此处虽然调用的是iter函数,但是实际函数并不会进入iter函数体内部,而是直接进入while True,在执行item = iterator.next()时,进入iter()函数体内部,且将yield关键字前面的代码作为next函数体,将yield关键字后面的数据作为next返回值
优点:无需写迭代器类,但是iter内部代码不够灵活
创建自定义Myrange类3.0版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def my_range(stop): number = 0 while number < stop: yield number number += 1
for num in my_range(5): print(num)
mr = my_range(5) iterator = mr.__iter__() while True: try: item = iterator.__next__() print(item) except StopIteration: break
|
找出列表中为偶数的元素
1 2 3 4 5 6 7 8 9 10 11 12
| list01 = [43, 43, 54, 56, 76, 87, 98]
def get_evens(list_target): for item in list_target: if item % 2 == 0: yield item
result = get_evens(list01) for item in result: print(item)
|
内置生成器
enumerate
语法:读写数据时使用 快捷键:itere+回车
1 2 3
| list = [1, 2, 3, 4, 5] for i, item in enumerate(list): print(i, item)
|
zip
语法
1 2 3 4
| list_name = ['张三', '李四', '王五'] list_age = [18, 19, 20] for item in zip(list_name, list_age): print(item)
|
输出
1 2 3
| ('张三', 18) ('李四', 19) ('王五', 20)
|