前言
本文主要介绍Python中的Iterable与Iterator,其中Iterable为可迭代对象,Iterator为迭代器对象。
目录:
a
Iterable与Iterator的介绍
可迭代协议: 含__iter__()方法。且可迭代对象中的__iter__()方法返回的是一个对应的迭代器。(如list对应的迭代器就是list_iterator)
迭代器协议:
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
最后来一个转换图:
▲生成器和迭代器的关系图
本文分享自 AI机器学习与深度学习算法 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!