网址导航网站如何做,用户登录入口,西安公司注册核名,银川做网站最好的公司有哪些生成器 Generators
要理解生成器#xff0c;首先要理解迭代器#xff0c;迭代器由以下三个部分组成#xff1a;
可迭代对象#xff08;iterable#xff09;迭代器#xff08;iterator#xff09;迭代#xff08;iteration#xff09;
1. 可迭代对象
只要定义了可以…生成器 Generators
要理解生成器首先要理解迭代器迭代器由以下三个部分组成
可迭代对象iterable迭代器iterator迭代iteration
1. 可迭代对象
只要定义了可以返回一个迭代器的__iter__方法的对象或者定义了可以支持下标索引的__getitem__方法。
2. 迭代器
只要定义了一个__next__方法的对象。
3. 迭代
从某个地⽅⽐如⼀个列表取出⼀个元素的过程。当我们使⽤⼀个循环来遍历某个东西时这就叫⼀个迭代。 生成器
生成器也是一种迭代器但是只能对其迭代一次。因为生成器没有把所有的值存在内存中而是在运行时生成值lazy。可以通过遍历来使用它们使用for循环或传递给任意可以进行迭代的函数和结构。
大多数生成器是以函数来实现的它们并不返回一个值而是yield一个值。 生成器最好的使用场景是不需要一次将所有计算的结果全部放在内存中或者一次读出全部的原始数据这样会造成很大的内存占用。
上述例子中我们用for循环来迭代这个生成器函数同样我们可以使用python的next()函数来获得迭代器的下一个元素。
基础数据类型list和str都是可迭代对象我们经常会使用for循环来获得每一个下标的数据。 但是我们发现不能调用next来迭代字符串和数据这是因为 数组和字符串是可迭代对象但不是迭代器。 使用for关键字迭代可迭代对象时for会自动获取到迭代器进行迭代。但是next只能对迭代器进行迭代因此我们需要使用到iter()函数来根据一个可迭代对象返回一个迭代器对象 同时next方法没有实现对StopIteration异常的捕捉在自己写的迭代器内一般需要额外进行迭代结束的编写。 测验
现在我们要写一个生成器迭代一个数组的时候不再是按顺序取出而是隔一个元素取出。
1. 函数式迭代器(yield)
def skip_elements(arr):for i in range(0, len(arr), 2): # 从索引0开始每次跨越2个元素yield arr[i]my_list [1, 2, 3, 4, 5, 6, 7, 8, 9]
gen skip_elements(my_list)for element in gen:print(element)2. 编写一个迭代器
class SkipElementsGenerator:def __init__(self, arr):self.arr arrself.index 0def __iter__(self):return selfdef __next__(self):if self.index len(self.arr):raise StopIterationelement self.arr[self.index]self.index 2 # 每次跳过一个元素return elementmy_list [1, 2, 3, 4, 5, 6, 7, 8, 9]
gen SkipElementsGenerator(my_list)for element in gen:print(element)SkipElementsGenerator是一个迭代器我们直接将要迭代的数组当成形参丢入以初始化迭代器。
注意因为要用for迭代迭代器因此迭代器也必须得是可迭代对象这里只需要简单实现__iter__函数并且返回self即可
Another Way
比较直观了解可迭代对象与迭代器的例子
class MyArray:def __init__(self, arr):self.arr arrdef __iter__(self):return SkipElementsGenerator(self.arr)class SkipElementsGenerator:def __init__(self, arr):self.arr arrself.index 0def __next__(self):if self.index len(self.arr):raise StopIterationelement self.arr[self.index]self.index 2 # 每次跳过一个元素return element# 创建自定义数组对象
my_list MyArray([1, 2, 3, 4, 5, 6, 7, 8, 9])# 使用生成器迭代元素
for element in my_list:print(element)原始数据是可迭代对象实现__iter__方法返回它的迭代器。 迭代器实现__next__方法迭代返回每一次迭代的值。
这个时候for循环直接迭代可迭代对象不像上一个例子一样是迭代迭代器。 for循环是先找到可迭代对象的迭代器 通过__iter__方法 然后对迭代器进行迭代 通过迭代器的__next__方法 这样写的话可以实现函数的解耦不会像上面代码一样还要实例化迭代器gen SkipElementsGenerator(my_list)然后人为迭代迭代器。 这样写的话只需要像原来一个实例化自定义的数据类型直接用for或者iter来获得迭代器代码中不会出现迭代器的名字无感使用。