1. 迭代器

迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件。

特点:

a)访问者不需要关心迭代器内部的结构,仅需通过next()方法或不断去取下一个内容

b)不能随机访问集合中的某个值 ,只能从头到尾依次访问

c)访问到一半时不能往回退

d)便于循环比较大的数据集合,节省内存

e)也不能复制一个迭代器。如果要再次(或者同时)迭代同一个对象,只能去创建另一个迭代器对象。enumerate()的返回值就是一个迭代器,我们以enumerate为例:

 a = enumerate(['a','b'])

for i in range(2):    #迭代两次enumerate对象
     for x, y in a:
         print(x,y)
     print(''.center(50,'-')) 

结果:

0 a
1 b
--------------------------------------------------
--------------------------------------------------

可以看到再次迭代enumerate对象时,没有返回值;

我们可以用linux的文件处理命令vim和cat来理解一下:

a) 读取很大的文件时,vim需要很久,cat是毫秒级;因为vim是一次性把文件全部加载到内存中读取;而cat是加载一行显示一行

b) vim读写文件时可以前进,后退,可以跳转到任意一行;而cat只能向下翻页,不能倒退,不能直接跳转到文件的某一页(因为读取的时候这个“某一页“可能还没有加载到内存中)

 

正式进入python迭代器之前,我们先要区分两个容易混淆的概念:可迭代对象和迭代器;

可以直接作用于for循环的对象统称为可迭代对象(Iterable)。

可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator)。

所有的Iterable均可以通过内置函数iter()来转变为Iterator。

1)可迭代对象

首先,迭代器是一个对象,不是一个函数;是一个什么样的对象呢?就是只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法,那么它就是一个可迭代对象。

python中大部分对象都是可迭代的,比如list,tuple等。如果给一个准确的定义的话,看一下list,tuple类的源码,都有__iter__(self)方法。

常见的可迭代对象:

a) 集合数据类型,如listtupledictsetstr等;

b) generator,包括生成器和带yield的generator function。

注意:生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator,关于生成器,继续往下看

如何判断一个对象是可迭代对象呢?可以通过collections模块的Iterable类型判断:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

2)迭代器

一个可迭代对象是不能独立进行迭代的,Python中,迭代是通过for ... in来完成的。

for循环在迭代一个可迭代对象的过程中都做了什么呢?

a)当for循环迭代一个可迭代对象时,首先会调用可迭代对象的__iter__()方法,然我们看看源码中关于list类的__iter__()方法的定义:

def __iter__(self, *args, **kwargs): # real signature unknown
    """ Implement iter(self). """
    pass

__iter__()方法调用了iter(self)函数,我们再来看一下iter()函数的定义:

def iter(source, sentinel=None): # known special case of iter
    """
    iter(iterable) -> iterator
    iter(callable, sentinel) -> iterator
    
    Get an iterator from an object.  In the first form, the argument must
    supply its own iterator, or be a sequence.
    In the second form, the callable is called until it returns the sentinel.
    """
    pass

iter()函数的参数是一个可迭代对象,最终返回一个迭代器

b) for循环会不断调用迭代器对象的__next__()方法(python2.x中是next()方法),每次循环,都返回迭代器对象的下一个值,直到遇到StopIteration异常。

>>> lst_iter = iter([1,2,3])
>>> lst_iter.__next__()
1
>>> lst_iter.__next__()
2
>>> lst_iter.__next__()
3
>>> lst_iter.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

这里注意:这里的__next__()方法和内置函数next(iterator, default=None)不是一个东西;(内置函数next(iterator, default=None)也可以返回迭代器的下一个值)

 c) 而for循环可以捕获StopIteration异常并结束循环;

总结一下:

a)for....in iterable,会通过调用iter(iterable)函数(实际上,首先调用的对象的__iter__()方法),返回一个迭代器iterator;

b)每次循环,调用一次对象的__next__(self),直到最后一个值,再次调用会触发StopIteration

c)for循环捕捉到StopIteration,从而结束循环

上面说了这么多,到底什么是迭代器Iterator呢?

任何实现了__iter____next__()(python2中实现next())方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值;

既然知道了什么迭代器,那我们自定义一个迭代器玩玩:

 1 class Iterator_test(object):
 2     def __init__(self, data):
 3         self.data = data
 4         self.index = len(data)
 5 
 6     def __iter__(self):
 7         return self
 8 
 9     def __next__(self):
10         if self.index <= 0 :
11             raise StopIteration
12         self.index -= 1
13         return self.data[self.index]
14 
15 iterator_winter = Iterator_test('abcde')
16 
17 for item in iterator_winter:
18     print(item)
View Code

相关文章:

  • 2021-09-22
  • 2021-09-25
  • 2022-12-23
  • 2021-11-21
  • 2022-01-21
  • 2021-05-25
  • 2021-11-28
  • 2021-07-16
猜你喜欢
  • 2021-09-03
  • 2022-12-23
  • 2021-09-19
  • 2021-11-28
  • 2021-11-15
相关资源
相似解决方案