一、迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
1. 可迭代对象
以直接作用于 for 循环的数据类型有以下几种: 一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等; 一类是 generator ,包括生成器和带 yield 的generator function。 这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。
2. 判断是否可以迭代
可以使用 isinstance() 判断一个对象是否是 Iterable 对象:
In [50]: from collections import Iterable In [51]: isinstance([], Iterable) Out[51]: True In [52]: isinstance({}, Iterable) Out[52]: True In [53]: isinstance('abc', Iterable) Out[53]: True In [54]: isinstance((x for x in range(10)), Iterable) Out[54]: True In [55]: isinstance(100, Iterable) Out[55]: False
3.迭代器
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用 isinstance() 判断一个对象是否是 Iterator 对象:
In [56]: from collections import Iterator In [57]: isinstance((x for x in range(10)), Iterator) Out[57]: True In [58]: isinstance([], Iterator) Out[58]: False In [59]: isinstance({}, Iterator) Out[59]: False In [60]: isinstance('abc', Iterator) Out[60]: False In [61]: isinstance(100, Iterator) Out[61]: False
4.iter()函数
生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。
把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数:
In [62]: isinstance(iter([]), Iterator) Out[62]: True In [63]: isinstance(iter('abc'), Iterator) Out[63]: True
迭代器一定是可迭代对象,但是可迭代对象不一定是迭代器。
list,truple,str这些都是可迭代对象,但是他们不一定是迭代器。迭代器本身不知道自己要执行多少次,所以可以理解为不知道有多少个元素,每调用一次next(),就会往下走一步,是惰性的。
迭代器提供了一种不依赖索引取值的方式,这样可以遍历没有索引的可迭代对象,比如字典、集合、文件等等,加载这一个元素至内存中随后释放,相比之下相当节省内存,这也是迭代器最大的优点,但是我们没有办法获取迭代器的长度,而且只能往后依次取值。
迭代是数据处理的基石。当内存中放不下数据集时,我们要找到一种惰性获取数据的方式,即按需一次获取一个数据项,这就是迭代器模式。
总结
凡是可作用于 for 循环的对象都是 Iterable 类型; 凡是可作用于 next() 函数的对象都是 Iterator 类型 集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter() 函数获得一个 Iterator 对象。
二、生成器
生成器是一个带 yield 语句的函数。一个函数或者子 程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果,返 回一个值给调用者并暂停执行。当生成器的 next()方法被调用的时候,它会准确地从离开地方继续
下面看示例:
1 def func(): 2 print('11111111') 3 yield [1] 4 print(2222222222) 5 yield 2 6 print(3333333333) 7 yield 3 8 9 ret=func() 10 r1=ret.__next__() 11 print(r1) 12 r2=ret.__next__() 13 print(r2) 14 r3=ret.__next__() 15 print(r3)
结果为:
1 11111111 2 13 2222222222 4 2 5 3333333333 6 3
由于 python 的 for 循环有 next()调用和对 StopIteration 的处理, 使用一个 for 循环而不是手 动迭代穿过一个生成器(或者那种事物的迭代器)总是要简洁漂亮得多。例:
1 def func(): 2 print('11111111') 3 yield [1] 4 print(2222222222) 5 yield 2 6 print(3333333333) 7 yield 3 8 ret=func() 9 for i in ret: 10 print(i)
结果同前面相同。
这些简单的例子应该让你有点明白生成器是如何工作的。除了 next()来获得下个生成的值,用户 可以将值回送给生成器[send()],在生成器中抛出异常,以及要求生成器退出[close()]
下面是一个展示了这些特性的,简单的例子。
1 def counter(start_at=0): 2 count = start_at 3 while True: 4 val = (yield count) if val is not None: 5 count = val 6 else: 7 count += 1
生成器带有一个初始化的值,对每次对生成器[next()]调用以 1 累加计数。用户已可以选择重 置这个值,如果他们非常想要用新的值来调用 send()不是调用 next()。这个生成器是永远运行的,所以如果你想要终结它,调用 close()方法。如果我们交互的运行这段代码,会得到如下输出:
1 >>> count = counter(5) 2 >>> count.next() 3 5 4 >>> count.next() 5 6 6 >>> count.send(9) 7 9 8 >>> count.next() 9 10 10 >>> count.close() 11 >>> count.next() 12 Traceback (most recent call last): 13 File "<stdin>", line 1, in <module> 14 StopIteration
三、 for循环的工作原理
dic = {"name": "egon", 'age': 18, 'gender': "male"} dic_iterator = dic.__iter__() while True: try: res = dic_iterator.__next__() print(res) except StopIteration: break for k in dic: print(k)
步骤1 dic_iterator = dic.__iter__() 步骤2 k=dic_iterator.__next__(),执行循环体代码 步骤3 循环往复,直到抛出异常,for循环会帮我们捕捉异常结束循环