1.Iterable与Iterator介绍
(1)iterable:具体应该叫做可迭代对象。他的特点其实就是我的序列的大小长度已经确定了(list,tuple,dict,string等)。他遵循可迭代的协议。
可迭代协议:含__iter__()方法。且可迭代对象中的__iter__()方法返回的是一个对应的迭代器。(如list对应的迭代器就是list_iterator)
(2)iterator:具体应该叫做迭代器的对象。他的特点就是他不知道要执行多少次,所以可以理解不知道有多少个元素,每调用一次__next__()方法,就会往下走一步,当然是用__next__()方法只能往下走,不会回退。是惰性的。这样我可以存很大很大的数据,即使是整个自然数,也可以很轻松的用迭代器来表示出来。他满足的是迭代器协议。
迭代器协议:含__iter__()方法。且方法返回的Iterator对象本身
含__next__()方法,每当__next__()方法被调用,返回下一个值,直到没有值可以访问,这个时候会抛出stopinteration的异常。
2.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
list.__next__()
AttributeError: 'list' object has no attribute '__next__'
print(type(list))
print(type(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
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
3.如何去判断Iterator和iterable
可以使用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)不一定。
4.如何自定义一个迭代器
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。
5.关于迭代问题
那什么是关于迭代问题呢?我们可以先看一下下面这段代码:
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