15、Python之迭代器

Python函数 / 2020-11-26

一、迭代器

1、何为迭代器?

以下内容搬运自Wikipedia/维基百科

迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。

数学中的迭代可以指函数迭代的过程,即反复地运用同一函数计算,前一次迭代得到的结果被用于作为下一次迭代的输入。

Python亦如此,迭代即重复取值,器即工具,合而为迭代取值的工具。

2、为何用迭代器?

提到需要重复取值,多数人脑海里估计会蹦出while、for!for底层其实就是调用迭代器,for和while一个非常大的区别是for不依赖索引,这也是Python给我们提供的一种不依赖于索引来取值的方式!

比如,我要把一个列表的值全给取出来!如下所示,这是while循环:

l1 = [1, 6, 'sanxi', 88]
i = 0
while i < 4:
    print(l1[i])
    i += 1

下面是for循环

l1 = [1, 6, 'sanxi', 88]
for i in l1:
    print(i)

3、如何用迭代器

用之前得先了解可迭代对象

3.1、可迭代对象

Iterable object,可迭代对象;Python中,凡是内置有__iter__方法的,都称之为可迭代对象,如列表、元组、字典、字符串、打开的文件等等!

3.2、迭代器对象

iterator object,迭代器;Python中,凡是内置有__iter__和__next__方法的对象都称之为迭代器对象!迭代器对象多数由可迭代对象转换而来!

迭代器有两个基本方法:

iter
next

# __iter__把可迭代对象转换为迭代器对象
>>> l2=[233,577,6868]
>>> l2.__iter__()
<list_iterator object at 0x7f96977600f0>
# 用iter()也是一样的效果
>>> l3={'sanxi':666}
>>> iter(l3)
<dict_keyiterator object at 0x7f969775aae8>
3.3、迭代取值
  • 调用__next__方法对迭代器对象进行迭代取值,每取一次值都会当做下一次迭代取值的初始值!

  • 当取完值后Python会报错并停止迭代!

  • 取完值后再进行迭代也会报错,因为迭代器是一次性的!

l1 = [1, 6, 'sanxi', 88]
l1_iterator = l1.__iter__()
while True:
    print(l1_iterator. __next__())
# 执行得到结果
1
6
sanxi
88
Traceback (most recent call last):
  File "/home/sanxi/PycharmProjects/untitled1/test.py", line 4, in <module>
    print(l1_iterator. __next__())
StopIteration

# 此时再进行迭代取值会报错,因为迭代器是一次性产品!
l1_iterator.__next__()

Traceback (most recent call last):
  File "/home/sanxi/PycharmProjects/untitled1/test.py", line 8, in <module>
    l1_iterator.__next__()
StopIteration

Python提供了一种语法为我们捕捉异常,如下所示:

l1 = [1, 6, 'sanxi', 88]
l1_iterator = l1.__iter__()
while True:
    try:
        print(l1_iterator.__next__())  #可能会报错的代码
    except StopIteration:  #except后面跟异常类型
        break  #捕捉成功后要执行的操作
        
# 执行得到结果,可以看到,已经没有错误信息了!
1
6
sanxi
88

上述例子看起来有点麻烦,为什么还非得用while?还不是为了给for增光添彩!

4、for循环拓展

4.1、for、while区别
  • while是条件循环,当条件为Flase时,结束循环!
  • for循环可以说是迭代循环,迭代取值完毕则结束循环
4.2、for循环原理
  • 先调用__iter__()方法得到一个迭代器对象
  • 接着对迭代器对象调用__next__()方法得到一个返回值,然后将该返回值赋值给in前面定义的变量
  • 循环步骤2,直到迭代取值完毕程序报错StopIteration,然后for会捕捉异常,并结束循环

其实就是上面while用了try那一套效果一样,因此上面的例子用for来执行就显得简洁许多!

l1 = [1, 6, 'sanxi', 88]
for i in l1:
    print(i)
# 执行得到结果
1
6
sanxi
88

5、迭代器优缺点

5.1、优点:
  • 为有序、无序的数据类型提供一种统一的循环取值方案

  • 惰性计算:对迭代器来说,同一时间它在内存中仅存在一个值,它可以存放无限大的值(你的内存有限。。。)

5.2、缺点:
  • 取值没有索引方便!因为迭代器只能从头读到尾,不能回头,不像索引取值那样想取哪个取哪个!正所谓开弓没有回头箭!
  • 一次性产品,若要重新迭代,只能重新生成迭代器!
世间微尘里 独爱茶酒中