您的位置 首页 > 腾讯云社区

轻松搞懂Python中Iterable与Iterator---Chenkc

前言

本文主要介绍Python中的Iterable与Iterator,其中Iterable为可迭代对象,Iterator为迭代器对象。

目录:

Iterable与Iterator的介绍;Iterable与Iterator的关系;如何判断Iterable和Iterator;如何自定义一个迭代器;关于迭代问题;

a

Iterable与Iterator的介绍

iterable:具体应该叫做可迭代对象。他的特点其实就是我的序列的大小长度已经确定了(list,tuple,dict,string等)。他遵循可迭代的协议。

可迭代协议: 含__iter__()方法。且可迭代对象中的__iter__()方法返回的是一个对应的迭代器。(如list对应的迭代器就是list_iterator)

iterator:具体应该叫做迭代器的对象。他的特点就是他不知道要执行多少次,所以可以理解不知道有多少个元素,每调用一次__next__()方法,就会往下走一步,当然是用__next__()方法只能往下走,不会回退。是惰性的。这样我可以存很大很大的数据,即使是整个自然数,也可以很轻松的用迭代器来表示出来。他满足的是迭代器协议。

迭代器协议:

含__iter__()方法。且方法返回的Iterator对象本身含__next__()方法,每当__next__()方法被调用,返回下一个值,直到没有值可以访问,这个时候会抛出stopinteration的异常。

b

Iterable与Iterator的关系

我们从上面的介绍可以看出。通俗的讲就是类中如果满足可迭代的协议也就是有__iter__()的时候就可以成为可迭代对象。同理如果一个类中有__iter__()和__next__()方法的时候也就可以称之为迭代器。那他们两个到底什么关系呢?

>>> from collections import Iterator, Iterable >>> help(Iterator) Help on class Iterator: class Iterator(Iterable) | Method resolution order: | Iterator | Iterable | builtins.object |**注解:从这里可以看出Iterable继承自object, Iterator继承自Iterable。 | Methods defined here: | | __iter__(self) | | __next__(self) | Return the next item from the iterator. When exhausted, raise StopIteration ...... >>> help(Iterable) Help on class Iterable: class Iterable(builtins.object) | Methods defined here: | | __iter__(self) ......

从上面的代码我们很清楚的看出Iterator继承iterable。这样我们就很清楚的看到了他们之间的关系了。

那我们说能不能把iterable转换Iterator呢?当然可以。可以通过iter()函数进行转换。其实说白了执行iter()方法就是去调用类中的__iter__()方法。其实前面也说了对于iterable如果执行了__iter__()方法他返回的是对应的itertor对象。如果Iterator调用__iter__()方法他返回的就是他自己(也就是一个迭代器)。

iter(iterable)-->iterator iter(iterator)-->iterator

那我们看看下面这段代码:

list = [1,2,3,4] list_iterator = iter(list) list.__next__() Traceback (most recent call last): File "G:/Python源码/iterable_test.py", line 3, in <module> list.__next__() AttributeError: 'list' object has no attribute '__next__' print(type(list)) print(type(list_iterator)) <class 'list'> <class 'list_iterator'>

我们的list是一个可迭代的对象。可以调用iter(list)说明我们的list中肯定有__iter__()方法。

list_iterator = iter(list)

list的源码中找到了这个方法。

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

从下面这段报错代码中我们可以看出,list中一定是没有__next__()方法的。

list.__next__() Traceback (most recent call last): File "G:/Python源码/iterable_test.py", line 3, in <module> list.__next__()

其实for循环中对于iterable对象有一个转换。

for x in [1,2,3,4,5]: pass

等价于===>

#先获取iterator对象 it = iter([1,2,3,4,5]) while True: try: #获取下一个值 x = next(it); except StopIteration: # 遇到StopIteration就退出循环 break

c

如何判断Iterable和Iterator

可以使用isinstance()判断一个对象是否是Iterable,Iterator对象:

from collections import Iterable,Iterator list = [1,2,3,4] list_iterator = iter(list) print(isinstance(list,Iterable),isinstance(list,Iterator))#True False print(isinstance(list_iterator,Iterable),isinstance(list_iterator,Iterator))#True True

从上面我们也可以看出。迭代器(iterator)一定是可迭代对象,但是可迭代对象(iterable)不一定。 d

如何自定义一个迭代器?

class EvenIterators(object): def __init__(self,n): self.stop = n self.value = -2 #实现__iter__()方法并返回自身(因为迭代器[实现__iter__和__next__]) def __iter__(self): return self def __next__(self): if self.value+2 > self.stop: raise StopIteration self.value += 2 return self.value e = EvenIterators(10) print(e.__next__()) print(e.__next__()) print(e.__next__()) print(e.__next__()) for en in e: print(en)

上面的EvenIterators类实现了一个偶数迭代器。从这个例子我们可以看出,只要我们实现了迭代协议,即方法__iter__()和next(),我们就实现了iterator。

e

关于迭代问题

那什么是关于迭代问题呢?我们可以先看一下下面这段代码:

list = [1,2,3,4] list_iterator = iter(list) for item in list_iterator: print("第一次打印--",item) for item in list_iterator: print("第二次打印--",item) 第一次打印-- 1 第一次打印-- 2 第一次打印-- 3 第一次打印-- 4

从上面可以看出,我的迭代器用完了就没有了。上面使用了第二个for循环没有打印出什么东西来,其实如果使用__next__()方法,没有数据的话也会抛出异常。那我们怎么去解决这个问题呢?我们可能想到我创建另一个迭代器,然后去遍历另外一个迭代器。但其实赋值赋给的是地址值,说白了就是他们访问的是同一块内存地址。这样我们就很清楚如何去解决了。因为list中没有其他的引用类型,所以这个时候使用浅copy和深copy都能解决问题。(当时不能直接使用list_iterator.copy()这种浅复制,因为会抛出没有这个方法的异常,也就是说iterator中没有这个copy()方法)

list = [1,2,3,4] list_iterator = iter(list) list_iterator2 = list_iterator print(list_iterator.__next__()) print(list_iterator2.__next__()) print(list_iterator.__next__()) print(list_iterator2.__next__())

我们不能对迭代器进行切片浅赋值,也不能直接调用copy方法进行浅复制(因为list中有,但是迭代器中没有对应的方法)。所以只能使用copy模块来进行浅复制和深复制。

浅复制import copy list = [1,2,3,4] list_iterator = iter(list) list_iterator2 = copy.copy(list_iterator) for item in list_iterator: print(item) for item in list_iterator2: print(item) 1 2 3 4 1 2 3 4深复制 import copy list = [1,2,3,4] list_iterator = iter(list) copy_list_iterator = copy.deepcopy(list_iterator) for item in list_iterator: print(item) for item in copy_list_iterator: print(item) 1 2 3 4 1 2 3 4

最后来一个转换图:

▲生成器和迭代器的关系图

---来自腾讯云社区的---Chenkc

关于作者: 瞎采新闻

这里可以显示个人介绍!这里可以显示个人介绍!

热门文章

留言与评论(共有 0 条评论)
   
验证码: