python中迭代器(转)

一、迭代器与for语句

网上许多文章说Python的for语句中,in关键字后面的对象是一个集合。例如

for i in [1,2,3]
    print i 

上面代码中in关键字后面的对象[1,2,3]是一个list,也是一个集合。

但in关键字后面的对象其实不必是一个集合。后面接一个序列对象也是合法的。 例如

myrange = MyRange(0, 10)
for i in myrange:
    print i  

上面代码中的myrange对象是一个序列对象,但不是集合。参见上一篇博文

事实上,for语句中in关键字后面的对象也不必是序列对象,它只需要是一个可迭代对象(Iterable)即可。

一个可迭代的对象需要满足下面两个条件之一:

  • 它实现了__iter__方法。该方法会返回一个迭代器对象。
  • 或者它是一个序列对象。

注意:如果一个类型实现了__iter__方法,那么在该方法中显式地给出了与该类型相关的迭代器如何构造。可是,对于序列类型来说,它有一个很天然的迭代器。因此,无需通过实现__iter__方法来显式定义。下一篇博文将介绍如何通过序列对象构造天然的迭代器。这里先介绍迭代器对象的严格定义。

一个迭代器,本质上也是一个序列。它需要实现下面两个方法。

  • next方法(老版本的Python叫__next__方法)。当第11次调用next方法时,会返回序列的第1个元素;当第2次调用next方法时,会返回序列的第2个元素;当序列中的元素耗尽,抛出StopIteration异常。
  • __iter__方法。前面说过__iter__方法通常返回迭代器对象。因此,对于一个迭代器来说,它的__iter__方法只需返回其本身即可。

通过上面的定义,我们知道,一个迭代器对象,也必是可迭代的。

下面的代码定义了一个迭代器。

class MyIterator:
    def __init__(self, start, end):
        self.start = start
        self.end = end  

    def next(self):
        if self.start >= self.end:
            raise StopIteration
        self.start = self.start + 1
        return self.start - 1  

    def __iter__(self):
        return self  

测试代码

myiter = MyIterator(0, 2)
print myiter.next()
print myiter.next()
print myiter.next()  

输出结果如下

0
1
Traceback (most recent call last):
  File "test.py", line 27, in <module>
    print myiter.next()
  File "test.py", line 16, in next
    raise StopIteration
StopIteration 

下面的代码测试在for语句中使用迭代器

myiter = MyIterator(0, 10)
for i in myiter:
    print i

输出结果

0
1
2
3
4
5
6
7
8
9 

二、iter方法

iter方法是Python的一个内建方法,它会返回一个迭代器对象。它定义如下

iter(o[, sentinel])

第一个参数o可以是一个可迭代对象,也可以是一个可调用对象。

当参数o是可迭代对象时,第二个参数可省。这里又分为两种情况。

  • 如果参数o实现了__iter__方法,则直接调用该方法,创建迭代器。
  • 如果参数o没有实现__iter__方法,那么它比是一个序列对象。iter方法根据该序列对象诱导出一个迭代器。

如果参数o是一个可调用对象时,iter方法返回的迭代器工作原理如下。

每次调用迭代器的next方法时,最终都会调用o方法。此时第2个参数sentinel必须给定。当o方法的返回值与sentinel相同时,抛出StopIteration异常。

一些例子

1. 由集合构造迭代器

myiter = iter([1,2,3])
myiter.next()
myiter.next()
myiter.next()
myiter.next()

输出结果

1
2
3
Traceback (most recent call last):
  File "test.py", line 27, in <module>
    print myiter.next()
StopIteration 

2. 由序列对象构造迭代器。

myiter = iter(MyRange(1, 4))
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()

MyRange的定义见博文

3. 由迭代器对象构造迭代器。

myiter1 = MyIterator(1, 4)
myiter2 = iter(myiter1)
print myiter1 == myiter2  

MyIterator的定义见博文。上面代码输出的值为True。

4. 由可调用对象构造迭代器。

myiter1 = MyIterator(1, 4)
myiter2 = iter(myiter1.next, 4)  

print myiter2.next()
print myiter2.next()
print myiter2.next()
print myiter2.next()  

输出结果

1
2
3
Traceback (most recent call last):
  File "test.py", line 27, in <module>
    print myiter.next()
StopIteration 

有兴趣的读者可以尝试下面代码的输出结果。

myiter2 = iter(myiter1.next, 3)
print myiter2.next()
print myiter2.next()
print myiter2.next()
print myiter2.next()
myiter2 = iter(myiter1.next, 5)
print myiter2.next()
print myiter2.next()
print myiter2.next()
print myiter2.next()

三、for循环工作原理

对于如下的for语句

for obj in iterable_obj:
   do something with obj  

首先会调用iter方法获取关于iterable_obj对象的迭代器,然后不断调用迭代器对象的next方法,直至抛出异常位置。

为了说明这一点,看下面的例子。

myiter = MyIterator(1, 4)
for i in myiter:
    pass  

print myiter.next()

上面代码会抛出StopIteration异常。因为在for语句阶段会将myiter迭代器对象的元素全部读完。MyIterator类的定义参见博文

到目前位置,我们有三种方式表示一个序列。它们是集合,序列对象和迭代器对象。

  • 集合(如列表,元组,字符串等)中的元素可读可写。当然不同的集合类型,可写的权限有所不同。例如列表中的元素可以随意添加,删除,修改。而元组中的元素虽然不能添加、删除和修改,但是我们可以对两个元组对象进行连接。当然,连接后会创建新的元组对象。
  • 序列对象中的元素可读但不可写。在基本的定义中,两个序列对象也不必支持元组对象那样的连接操作。这样的好处是,在有的情况下,我们不必开辟专门的内存空间保存序列对象中的所有元素。
  • 迭代器对象中的元素也是可读不可写的。但是,迭代器对读的权限做了一个限制,就是只能从头至尾读一遍。迭代器对象的优势在于它有的时候比序列对象更加灵活。通常情况下,序列对象中的元素顺序是不能变的。而对于迭代器对象来说,我们只需要指定不同的next方法,就能实现不同的读取顺序。一个比较经典的例子,就是我们可以实现一个迭代器类,同时支持树的深度优先和广度优先遍历。显然用迭代器实现这个功能比用序列来实现要简单许多。

四、序列诱导迭代器

如果我们自己要实现iter方法,通过一个序列对象构造出一个迭代器,会怎么做呢?

首先需要定义一个迭代器类。

class MyIteratorFromSequence:
    def __init__(self, sequence):
        self.start = 0
        self.sequence = sequence  

    def next(self):
        if self.start >= len(self.sequence):
            raise StopIteration
        self.start = self.start + 1
        return self.sequence[self.start - 1]  

    def __iter__(self):
        return self  

上面的代码和博文中MyIterator类的定义完全类似,所不同的是,每次执行next方法,返回的不再是start - 1,而是序列对象的第start - 1个元素。

测试这个迭代器的运行效果

mylist = [1, 3, 5, ‘a‘, ‘b‘, ‘c‘]
myiter = MyIteratorFromSequence(mylist)
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next() 

输出结果为

1
3
5
a
b
c

有了MyIterorFromSequence的定义,iter方法的实现就很简单了。

def myiter(sequence):
    return MyIteratorFromSequence(sequence)  

注意:上面的代码实现的功能比内置的iter方法要简单许多。因为我们只实现了序列对象到迭代器对象的构造。

有了上面的分析,下面代码的输出就在情理之中了。

mylist = [1, 2, 3]
myiter = iter(mylist)
mylist.append(4)  

for i in myiter:
    print i  

输出结果为

1
2
3
4 

转自:http://blog.csdn.net/hedan2013/article/details/55519047

时间: 2024-09-29 18:10:12

python中迭代器(转)的相关文章

python中迭代器和生成器的区别

1 #!/usr/bin/python 2 def power(values): 3 for value in values: 4 print "powing %s" % value 5 yield value 6 def add(values): 7 for value in values: 8 if value % 2 == 0: 9 yield value + 3 10 else: 11 yield value + 2 12 elements = [1, 4, 7, 9, 12,

python中迭代器和生成器。

前言:很多python教程中,对python的解释不容易理解,本文记录自己的理解和体会,是对迭代器和生成器的初步理解. 迭代器: 迭代器的实质是实现了next()方法的对象,常见的元组.列表.字典都是迭代器. 迭代器中重点关注两种方法: __iter__方法:返回迭代器自身.可以通过python内建函数iter()调用. __next__方法:当next方法被调用的时候,迭代器会返回它的下一个值,如果next方法被调用,但迭代器没有只可以返回,就会引发一个StopIteration异常.该方法可

python中的生成器和迭代器

1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. 1.1 使用迭代器的优点 对于原生支持随机访问的数据结构(如tuple.list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值).但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式. 另外,迭代器的一大优点是不要求事

迭代器就是重复地做一些事情,可以简单的理解为循环,在python中实现了__iter__方法的对象是可迭代的,实现了next()方法的对象是迭代器,这样说起来有

迭代器就是重复地做一些事情,可以简单的理解为循环,在python中实现了__iter__方法的对象是可迭代的,实现了next()方法的对象是迭代器,这样说起来有点拗口,实际上要想让一个迭代器工作,至少要实现__iter__方法和next方法.很多时候使用迭代器完成的工作使用列表也可以完成,但是如果有很多值列表就会占用太多的内存,而且使用迭代器也让我们的程序更加通用.优雅.pythonic.下边是一个例子,从里边你会感受到不用列表而用迭代器的原因. #!/usr/bin/env python #c

python中“生成器”、“迭代器”、“闭包”、“装饰器”的深入理解

一.生成器 1.什么是生成器? 在python中,一边循环一边计算的机制,称为生成器:generator. 2.生成器有什么优点? 1.节约内存.python在使用生成器时对延迟操作提供了支持.所谓延迟,是指在需要的时候才产生结果,而不是立即产生结果.这样在需要的时候才去调用结果,而不是将结果提前存储起来要节约内存.比如用列表的形式存放较大数据将会占用不少内存.这是生成器的主要好处.比如大数据中,使用生成器来调取数据结果而不是列表来处理数据,因为这样可以节约内存. 2.迭代到下一次的调用时,所使

Python中的内置模块与生成器迭代器-day5

Python3 中内置模块 Python中的列表生成式 Python生成器 Python迭代器 一.Python中的内置模块 PS:作为一个新手如果你不想使用IDE又想使用Python中的自动补全,可以下载使用ipython.下面实例中也大多是ipython输入和输出的内容. 安装ipython:pip3 install ipython Python3-内置函数 - abs() 绝对值 - all() 都为真 - any() 有一个为真 - ascii() 把字符串转换成ASCII - bin(

Python中的迭代器、生成器

什么是迭代器 迭代器即迭代的工具 迭代是一个重复的过程,每一次重复即一次迭代,且每次迭代的结果都是下一次迭代的初始值 while True: #这里只是单纯的重复,不是迭代 print('-----') l = [1,2,3] count = 0 while count <= len(l): #这里是迭代 print(l[count]) count += 1 迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异

Python中的迭代器和生成器,以及装饰

一.迭代器 它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__和__next__()方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常,至于它们到底是如何实现的这并不重要. 迭代器是访问集合内元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束. (1)迭代器的四大特性 1.跌代集合,字符串,有序依次---

Python中生成器,迭代器,以及一些常用的内置函数.

知识点总结 生成器 生成器的本质就是迭代器. 迭代器:Python中提供的已经写好的工具或者通过数据转化得来的. 生成器:需要我们自己用Python代码构建的 创建生成器的三种方法: 通过生成器函数 通过生成器推导式 python内置函数或者模块提供 生成器函数 yield:一个yield对应一个next,next超过yield数量,就会报错,与迭代器一样. yield与return的区别: return一般在函数中只设置一个,他的作用是终止函数,并传给函数的执行者返回值 yield在生成器中可