Python—戏说迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退
1. 可迭代对象
我们已经知道可以对list、 tuple、 str等类型的数据使用for…in…的循环语法从其中依次拿到数据进行使用, 我们把这样的过程称为遍历, 也叫迭代
>>> for i in 100:
... print(i)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
# int整型不是iterable, 即int整型不是可以迭代的
# 我们⾃定义⼀个容器MyList⽤来存放数据, 可以通过add⽅法向其中添加数据
>>> class MyList(object):
... def __init__(self):
... self.container = []
... def add(self, item):
... self.container.append(item)
...
>>> mylist = MyList()
>>> mylist.add(1)
>>> mylist.add(2)
>>> mylist.add(3)
>>> for num in mylist:
... print(num)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyList' object is not iterable
>>>
# MyList容器的对象也是不能迭代的
2.如何判断一个对象是否可以迭代
可以使用isinstance()判断一个对象是否是Iterable对象:
In [50]: from collections import Iterable
In [51]: isinstance([], Iterable)
Out[51]: True
In [52]: isinstance({}, Iterable)
Out[52]: True
In [53]: isinstance('abc', Iterable)
Out[53]: True
In [54]: isinstance(mylist, Iterable)
Out[54]: False
In [55]: isinstance(100, Iterable)
Out[55]: False
3.可迭代对象的本质
可迭代对象进行迭代使用的过程,每发生一次(即在for。。。in。。。中每循环一次)都会返回对象中的下一条数据,一直想后读取数据迭代了所有数据后结束。那么,这个过程应该有一个“人”去记录每次访问到了第几条数据,以便每次迭代都可以返回下一条数据。
把进行数据迭达的人成为迭代器(Iterator)
可迭代对象的本质就是可以向我们提供一个这样的中间”人“,即迭代器帮助我们对其进行迭达遍历使用。
可迭代对象通过__iter__
方法向我们提供一个迭代器,我们在迭代一个可迭代对象时,实际上是先获取该对象提供的一个迭代器,然后通过这个迭代器来一次获取对象中的每一个数据
换句话说,一个具备__iter__
方法的对象,就是一个可迭代对象
>>> class MyList(object):
... def __init__(self):
... self.container = []
... def add(self, item):
... self.container.append(item)
... def __iter__(self):
... """返回⼀个迭代器"""
... # 我们暂时忽略如何构造⼀个迭代器对象
... pass
...
>>> mylist = MyList()
>>> from collections import Iterable
>>> isinstance(mylist, Iterable)
True
>>>
# 这回测试发现添加了__iter__⽅法的mylist对象已经是⼀个可迭代对象了
4.iter()函数和next()函数
list,tuple都是可迭代对象,可以通过iter()函数获取这些可迭代对象的迭代器。然后对获取到的迭代器不断使用next()函数获取下一条数据。i
>>> li = [11, 22, 33, 44, 55]
>>> li_iter = iter(li)
>>> next(li_iter)
11
>>> next(li_iter)
22
>>> next(li_iter)
33
>>> next(li_iter)
44
>>> next(li_iter)
55
>>> next(li_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
5.如何判断一个对象为迭代器
使用isinstance()
判断
In [56]: from collections import Iterator
In [57]: isinstance([], Iterator)
Out[57]: False
In [58]: isinstance(iter([]), Iterator)
Out[58]: True
In [59]: isinstance(iter("abc"), Iterator)
Out[59]
6. 迭代器Iterator
构造一个迭代器,就是要实现__next__
方法。但是,python要求迭代器本身也是可迭代的,所以还需要为迭代器实现__iter__
方法,而__iter__
方法要返回一个迭代器,迭代器自身正是一个迭代器,所以__iter__
方法返回自身即可
#版本1
import time
from collections import Iterable
from collections import Iterator
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
"""
如果想要一个对象称为一个可以迭代对像,即可以使用for
那必须使用__iter__()方法
"""
return ClassIterator(self)
class ClassIterator(object):
def __init__(self, obj):
self.obj = obj
self.num = 0
def __iter__(self):
pass
def __next__(self):
if self.num < len(self.obj.names):
ret = self.obj.names[self.num]
self.num += 1
return ret
else:
raise StopIteration
classmate = Classmate()
classmate.add("duyu")
classmate.add("duandf")
classmate.add("dsadjf")
#print("判断classmate是否是可以迭代对象:",isinstance(classmate, Iterable))
#classmate_iterator = iter(classmate)
#print("判断classmate_iterator是否是可以迭代对象:",isinstance(classmate_iterator, Iterator))
#print(next(classmate_iterator))
for name in classmate:
print(name)
time.sleep(1)
#版本2
import time
from collections import Iterable
from collections import Iterator
class Classmate(object):
def __init__(self):
self.names = list()
self.num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
"""
如果想要一个对象称为一个可以迭代对像,即可以使用for
那必须使用__iter__()方法
"""
return self
def __next__(self):
if self.num < len(self.names):
ret = self.names[self.num]
self.num += 1
return ret
else:
raise StopIteration
classmate = Classmate()
classmate.add("duyu")
classmate.add("duandf")
classmate.add("dsadjf")
#print("判断classmate是否是可以迭代对象:",isinstance(classmate, Iterable))
#classmate_iterator = iter(classmate)
#print("判断classmate_iterator是否是可以迭代对象:",isinstance(classmate_iterator, Iterator))
#print(next(classmate_iterator))
for name in classmate:
print(name)
time.sleep(1)
7 for…in…循环的本质
for item in Iterable
先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法获取下一个值并将其赋值给item,当遇到StopIteration的异常后退出循环
8.应用场景
迭代器最核心功能就是通过next()函数调用返回下一个数据值。如果每次返回的数据不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的,那么也就意味着可以不用再依赖一个已有的数据集合,也就是说不用再将所有要迭代的数据都一次性缓存下来供后续依次读取,这个可以可以节省大量的存储(内存)空间
- 斐波那契数列(迭代器实现)
#!/usr/bin/env python
# coding=utf-8
class Fibonacci(object):
def __init__(self, all_num):
self.all_num = all_num
self.current_num = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.current_num < self.all_num:
ret = self.a
self.a, self.b = self.b, self.a + self.b
self.current_num += 1
return ret
else:
raise StopIteration
fibo = Fibonacci(10)
for num in fibo:
print(num)