十二. Python基础(12)--生成器
1 ● 可迭代对象(iterable)
An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict and file and objects of any classes you define with an __iter__() or __getitem__() method. An iterable object works as the source of items in for loops, comprehensions and tuple unpacking. Iterables are objects that produce an iterator when they are passed to the iter() builtin. |
一些iterable将所有值都存储在内存中,比如list,而另一些并不是这样,比如我们下面将讲到的iterator. |
Python内置的可迭代对象: range(),str,list,tuple,dict,set |
2 ● 迭代器(iterator)
An object representing a stream of data. Repeated calls to the iterator's __next__ () method return successive items in the stream. When no more data are available a StopIteration exception is raised instead. Also, Iterators are required to have an __iter__() method that returns the iterator object itself (返回迭代器对象自身), so every iterator is also iterable. ※ 迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。 |
python的迭代器为什么一定要实现__iter__方法? iterator实现(implement)的__iter__是为了兼容iterable的接口,从而让iterator成为iterable的一种实现. |
Python内置的迭代器: iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o |
3 ● 判断是否为可迭代对象/迭代器
from collections import Iterable print(isinstance('aaa', Iterable)) # True print(isinstance('aaa'.__iter__(), Iterable)) # True, Iterator属于Iterable |
from collections import Iterator print(isinstance([1,2,3], Iterator)) # False print(isinstance([1,2,3].__iter__(), Iterator)) #True |
4 ● 可迭代对象协议(iterable protocol)/迭代器协议(iterator protocol)
可迭代对象协议: 对象内部实现了__iter__方法。 ※ 如何确定一个对象是否可迭代? --看是否包含__iter__()方法. |
迭代器协议: 对象内部实现了__iter__()方法和__next__()方法. ※ 更详细的说法: 对象必须提供一个next方法, 执行该方法要么返回迭代中的下一项, 要么就引起一个StopIteration异常, 以终止迭代 (只能往后走不能往前退). |
__iter__()方法: 返回一个迭代器对象 __next__()方法: 返回迭代器的下一个项目 |
5● 迭代器的表象&本质
表象: Python从迭代器中一个一个的取值. |
本质:把标志控制的循环 和 计数控制的循环统一为一种控制的循环,即迭代器控制的循环,每一次迭代操作中对迭代器的修改就等价于修改标志或计数器. |
6 ● 生成器(generator)&生成器函数(generator function)&生成器表达式(generator expression)
generator: (自己实现的iterator) Both generator functions and generator expressions are generators, by which we can build an iterator by ourseleves. 迭代器就是我们自己就可以通过生成器函数和生成器表达式实现的迭代器. 生成器一定是迭代器, 但迭代器不一定是生成器.
※ 调用生成器函数时,每次执行到yield语句,生成器的状态将被冻结起来,并将结果返回__next__调用者。冻结意思是局部的状态都会被保存起来,包括局部变量绑定、指令指针。确保下一次调用时能从上一次的状态继续。 生成器的特点(同样适用于迭代器): ① 节省内存(因为惰性计算): iterate through potentially huge sequences without creating and storing the entire sequence in memory at once. ② 一个生成器只能运行一次: 生成器中的每个值只能按顺序取一次, 并且不能返回取值, 取完后就不能再从生成器中取值了; ③ 惰性运算: 生成器只有在被调用的时候才会生成相应的数据(用__next__()、 for、list调用, 或被其它函数调用), 反之就不会生成--因此python适合大数据处理 ④ 无法复制一个生成器 (无论是直接复制给另一个对象, 还是进行深浅拷贝, 都不能复制生成器, 因此要再次进行迭代只能重新生成一个新的迭代器对象) ※⑤ 可以把非线性化的处理转换成线性化的方式来进行处理。 |
迭代器函数(generator function): A function that has the yield keyword in its body. 1. 概念:带yield关键字的函数就是生成器函数 2. 特点(也是迭代器的特点, 见上): 3. 从生成器中取值的方法: ①__next__() 有几个yield就可以取几次 ② for循环取值 正常取 for i in g: ③用其他数据类型进行强制转换, 例如, list(g)返回一个列表, 里面装着生成器中的所有内容 ※ 上面三种取值方法不要混合使用 |
迭代器表达式/迭代器推导式(generator expression/generator comprehension): An expression enclosed in parenthesis using the same syntax of a list comprehension, but returning a generator instead of a list. A generator expression can be understood as a lazy version of a list comprehension. |
7 ● 几个概念的关系
※ A generator is a subtype of iterator; an iterator is an iterable. ※ 迭代器 = 可迭代对象.__iter__() ※ 迭代器分为①先天的(如文件句柄); ②后天的(可迭代对象.__iter__(), 如range返回的可迭代对象) |
8 ● 生成迭代器的两种方法
# 使用对象内置的__iter__()方法生成迭代器 L1 = [1,2,3] I1 = L1.__iter__() print(I1) print(I1.__next__()) #1, python2还可以写成print I1.next(), python3还可以写成print(next(I1)) print(I1.__next__()) # 下面是容错处理: while True: try: print(I1.__next__()) except StopIteration: break |
# 使用内置工厂函数生成迭代器 L1 = [1,2,3] I2 = iter(L1) print(I2) print(I2.next()) # 1, 在python3中, 会提示没有next()这个方法,只能用__next__()或next(iterator) print(I2.next()) |
9 ● for和可迭代对象和迭代器
for loop可作用于(work on)可迭代对象和迭代器. for循环的本质: ① 循环不是迭代器的可迭代对象 :不具备__next__()方法的可迭代对象.__iter__(), 得到了一个迭代器, 然后调用迭代器的__next__()方法 ② 循环迭代器:直接调用迭代器的__next__()方法 |
import time start_time_1 = time.time() for i in range(200000000): pass time_cost_1 = time.time() - start_time_1 print('time_cost_1:',time_cost_1)
time.sleep(5)
import time start_time_2 = time.time() for i in range(200000000).__iter__(): pass time_cost_2 = time.time() - start_time_2 print('time_cost_2:',time_cost_2) |
time_cost_1: 21.656238555908203 time_cost_2: 24.198384284973145 # 迭代器可以节省内存, 但速度不一定快. |
10 ● 生成器表达式的案例
number_thing = (number for number in range(1, 6)) 圆括号之间的是生成器推导式(generator comprehension),它返回的是一个生成器对象(generator object): >>> type(number_thing) <class 'generotor'> 你可以直接对生成器对象进行迭代,如下所示: >>> for number in number_thing: ... print(number) ... 1 2 3 4 5 或者通过调用list() 函数: >>> number_list = list(number_thing) >>> number_list [1, 2, 3, 4, 5] |
※ A generator can be run only once. Lists, sets, strings, and dictionaries exist in memory, but a generator creates its values on the fly(即时, 立刻, 马上) and hands them out one at a time through an iterator. It doesn't remember them, so you can't restart or back up a generator. 一个生成器只能运行一次。列表、集合、字符串和字典都存储在内存中,但是生成器仅在运行中产生值,不会被存下来,所以不能重新使用或者备份一个生成器。 例如: >>> try_again = list(number_thing) >>> try_again |
11 ● eager and lazy(急切和懒惰)
An iterable object that builds all its items at once. In Python, a list comprehension is eager. Contrast with lazy. |
An iterable object which produces items on demand. In Python, generators are lazy. Contrast with eager. |
12 ● 生成器最相关的面试题
① 生成器中的内容需要使用__next__()、 for、list主动获取才会生成, 反之就不会生成--惰性运算 ② 使用__next__()、for、list从迭代器中取值后, 迭代器中的内容必然会减少或者完全用光. |
13 ● 监听文件输入的内容
import time def tail(filename): f = open(filename, encoding= "utf-8") f.seek(0,2) while True: line = f.readline() if not line: time.sleep(0.1) # 避免因为while True的原因导致内存消耗过大, continue else: yield line
tail_gen = tail("test.txt") for line in tail_gen: print(line, end = "") |