python将list转换为迭代器代码_python 迭代器(转)

迭代器

迭代器是在python2.2中被加入的,它为类序列对象提供了一个类序列的接口。有了迭代器可以迭代一个不是序列的对象,因为他表现出了序列的行为。当在python中使用for循环迭代一个对象时,调用者几乎分辨不出他迭代的是一个迭代器对象还是一个序列对象,因为python让他(迭代器)像一个序列那样操作。

如何迭代

本质上说迭代器是个对象,但是这个对象有个特殊的方法next()(在python3中使用__next__()代替了next方法)。当使用for循环来遍历整个对象时候,就会自动调用此对象的__next__()方法并获取下一个item。当所有的item全部取出后就会抛出一个StopIteration异常,这并不是错误的发生,而是告诉外部调用者迭代完成了,外部的调用者尝试去捕获这个异常去做进一步的处理。

不过迭代器是有限制的,例如

不能向后移动

不能回到开始

也无法复制一个迭代器。

因此要再次进行迭代只能重新生成一个新的迭代器对象。

获取迭代器

对于python内置的可迭代(iterable)对象,可以通过内置的iter()函数来获取相应的迭代器对象。

Python a = [1,2,3,45]type(a)list a =iter(a)type(a)list_iterator1

2

3

4

5

6

7

8

9a = [1,2,3,45]type(a)lista =iter(a)type(a)list_iterator

这样就获取了list相应的迭代器对象。

我们来看一下该迭代器对象的属性:

Pythondir(a)['__class__','__delattr__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__iter__','__le__','__length_hint__','__lt__','__ne__','__new__','__next__','__reduce__','__reduce_ex__','__repr__','__setattr__','__setstate__','__sizeof__','__str__','__subclasshook__']可见此迭代对象具有两个特殊的成员方法__iter__()和__next__(),这两个方法便是支持迭代器协议所需要实现的方法。其中__iter__()方法返回迭代器对象本身,__next__()方法返回容器的下一个元素,直到结尾抛出StopIteration异常。

我们来测试一下这个list_iterator对象的这两个方法:

__iter__()返回的对象就是迭代器对象本身。

Pythona = [1,2,3,45] a =iter(a)a.__iter__()aa isa.__iter__()TrueIn [1]: a = [1,2,3,45]

In [2]: a =iter(a)

In [3]: a.__iter__()

Out[3]: In [4]: a

Out[4]: In [5]: a isa.__iter__()

Out[5]: True

In [6]:

__next__()方法返回容器中的值直到结尾。

Python

In [6]: a.__next__()

Out[6]: 1In [7]: a.__next__()

Out[7]: 2In [8]: a.__next__()

Out[8]: 3In [9]: a.__next__()

Out[9]: 45In [10]: a.__next__()------------------------------------------StopIteration Traceback (most recent call last) in ()----> 1a.__next__()In [6]: a.__next__()

Out[6]: 1In [7]: a.__next__()

Out[7]: 2In [8]: a.__next__()

Out[8]: 3In [9]: a.__next__()

Out[9]: 45In [10]: a.__next__()------------------------------------------StopIteration Traceback (most recent call last) in ()----> 1a.__next__()

StopIteration:

In [11]:2. 创建迭代器对象

除了使用iter()函数将内置的序列对象转换成相应的迭代器,我们可以自己实现迭代器协议创建迭代器对象,要实现迭代器协议也就是要在类中实现__iter__()和__next__()方法。

下面我写一个与list_iterator相同行为的迭代器:

Pythonclass ListIter(object):

def __init__(self, data):

self.__data=data

self.__count= 0def __iter__(self):returnself

def __next__(self):if self.__count

val=self.__data[self.__count]

self.__count+= 1

returnvalelse:

raise StopIteration

class ListIter(object):

def __init__(self, data):

self.__data=data

self.__count= 0def __iter__(self):returnself

def __next__(self):if self.__count

val=self.__data[self.__count]

self.__count+= 1

returnvalelse:

raise StopIteration

我们就可以使用for循环来遍历这个迭代器了:

Python

In [16]: a = ListIter([1,2,3,4,5])

In [17]: for i ina:

....: print(i)

....:In [16]: a = ListIter([1,2,3,4,5])

In [17]: for i ina:

....: print(i)

....:对于迭代器对象,使用for循环遍历整个数组其实是个语法糖,他的内部实现还是通过调用对象的__next__()方法。

实际上他内部的工作原理应该是这样的:

a= ListIter([1, 2, 3, 4, 5])whileTrue:try:

i=a.__next__()

except StopIteration:break

//do something in for loop

print(i)a= ListIter([1, 2, 3, 4, 5])whileTrue:try:

i=a.__next__()

except StopIteration:break

//do something in for loop

print(i)

迭代器支持多次迭代

正如前面所说的迭代器对象不支持重新迭代,也就是同一个迭代器对象无法多次迭代,如:

Python

In [19]: a = ListIter([1,2,3,4,5])

In [20]: [i for i ina]

Out[20]: [1, 2, 3, 4, 5]

In [21]: [i for i ina]

Out[21]: []In [19]: a = ListIter([1,2,3,4,5])

In [20]: [i for i ina]

Out[20]: [1, 2, 3, 4, 5]

In [21]: [i for i ina]

Out[21]: []

In [22]:

可见,当我再次迭代迭代器a的时候便只返回了空列表,这是因为for循环直接捕获了StopIteration异常。如果要再次迭代生成列表的话只能重新生成一个新的迭代器对象。

为了能够解决这个问题,可以分别定义一个可迭代对象(iterables)和迭代器对象(iterator).

插入小插曲:

对于可迭代对象和迭代器对象,我的理解是:

可迭代对象是实现了__iter__()方法的对象,__iter__()可以返回一个迭代器对象。

迭代器对象是实现了__next__()方法的对象,其中他的__iter__()返回的是迭代器对象本身。

我把代码做了修改,如下:

Pythonclass ListIterable(object):

def __init__(self, data):

self.__data=data

def __iter__(self):

print("call iterable __iter__().")returnListIterator(self.__data)class ListIterator(object):

def __init__(self, data):

self.__data=data

self.__count= 0def __iter__(self):

print("call iterator __iter__().")returnself

def __next__(self):

print("call iterator __next__().")if self.__count

val=self.__data[self.__count]

self.__count+= 1

returnvalelse:

raise StopIteration

class ListIterable(object):

def __init__(self, data):

self.__data=data

def __iter__(self):

print("call iterable __iter__().")returnListIterator(self.__data)class ListIterator(object):

def __init__(self, data):

self.__data=data

self.__count= 0def __iter__(self):

print("call iterator __iter__().")returnself

def __next__(self):

print("call iterator __next__().")if self.__count

val=self.__data[self.__count]

self.__count+= 1

returnvalelse:

raise StopIteration

为了知道python何时调用__iter__()方法,我添加了一个printf函数来做标记。

现在把这两个类导入到当前空间中:

Python

In [1]: from list_iter import *In [2]: a = ListIterable([1,2,4,5,6])

In [3]: b =a.__iter__()

call iterables __iter__().

In [4]: a

Out[4]: In [5]: b

Out[5]: In [1]: from list_iter import *In [2]: a = ListIterable([1,2,4,5,6])

In [3]: b =a.__iter__()

call iterables __iter__().

In [4]: a

Out[4]: In [5]: b

Out[5]: In [6]:

可见a是iterable对象(实现了__iter__()),b是iterator对象(实现了__next__())。

下面看看这样做是不是就可以重复多次迭代了:

Python

In [6]: [i for i ina]

call iterable __iter__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

Out[6]: [1, 2, 4, 5, 6]

In [7]: [i for i ina]

call iterable __iter__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

Out[7]: [1, 2, 4, 5, 6]In [6]: [i for i ina]

call iterable __iter__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

Out[6]: [1, 2, 4, 5, 6]

In [7]: [i for i ina]

call iterable __iter__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

call iterator __next__().

Out[7]: [1, 2, 4, 5, 6]

In [8]:

重复迭代是可以了,从输出中我们可以看出一些什么来

我们在使用迭代工具对iterable对象进行迭代的时候首先调用的是iterable的__iter__()方法,返回一个迭代器对象,也就是ListIterator的实例。

然后再遍历的时候是调用iterator的next方法输出值。

这样就可以解释了为什么这样处理能够多次迭代了,因为每次使用迭代工具迭代的时候都会调用__iter__()返回一个新的迭代器对象,这样就相当于创建多个迭代器了,自然可以看起来是重复迭代了!

可变对象和迭代器

在迭代可变对象时候,一个序列的迭代器只是记录当前到达了序列中的第几个元素,所以如果在迭代过程中改变了序列的元素。更新会立即反应到所迭代的条目上。

我写了个测试看了下,的确:

Python

In [13]: c = [1,2,3,4,5]

In [14]: d =iter(c)

In [15]: for i inc:

....: print(i)

....: c.remove(i)

....:In [13]: c = [1,2,3,4,5]

In [14]: d =iter(c)

In [15]: for i inc:

....: print(i)

....: c.remove(i)

....:可见上面边迭代边删除列表的元素,但是最后却只输出了1,3, 5,这是为啥?

既然迭代器只记得是在列表中第几个元素,那么当在第0个元素的时候将会输出1然后删除1,这是列表变成了

Python

[2, 3, 4, 5]1[2, 3, 4, 5]

但是迭代器记得我是在第二个位置上面,就指向了列表中的第二个位置上,也就是3,然后输出3.

以此类推,最后只能输出1,3,5了。

如果我猜测的没错的话,剩余的列表应该只剩下2和4了:

Python

In [17]: c

Out[17]: [2, 4]1

2In [17]: c

Out[17]: [2, 4]

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值