迭代是访问集合元素的一种方法,迭代器是一个可以记住遍历位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不能后退。
1、可迭代对象
我们已经知道可以对list
,tuple
,str
等类型的数据可以使用for...in...
的循环语法从其中一次拿到数据进行使用,我们把这样的过程成为遍历,也叫迭代
但是
(1)如何判断一个对象是否可以迭代
from collections import Iterable
print(isinstance(对象, Iterable))
# 例如:
print(isinstance([11,22,33], Iterable)) # 返回为True,则证明可以迭代
(2)构建可迭代对象
from collections import Iterable
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
# 如果想要对象成为一个 可迭代对象(可以使用for),那么必须实现__iter__方法
pass
classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
print('判断classmate是否是可以迭代的对象:', isinstance(classmate, Iterable))
运行结果:
判断classmate是否是可以迭代的对象: True
可以看到,当加入__iter__
方法的时候,classmate
变成了一个可迭代的对象,如果去掉的话,那么classmate
方法变得不可迭代,尽管其中的变量为列表,也不支持迭代。
2、构建迭代器
这里有两种方法,我将挨个解释。
(1)第一种方法:
实例
from collections import Iterator
import time
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
# 如果想要对象成为一个 可迭代对象(可以使用for),那么必须实现__iter__方法
return ClassInterator(self)
class ClassInterator(object):
def __init__(self,obj):
self.obj = obj # 通过实例化参数获取Classmate()对象的names属性
self.current_num = 0
def __iter__(self):
pass
# 构造迭代器,返回Classmate()对象的names属性
def __next__(self):
# 保证列表索引不越界的情况下,挨个返回列表names的内容
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
classmate_interator = iter(classmate)
print('判断classmate_interator是否是迭代器:', isinstance(classmate_interator, Iterator))
for i in classmate:
print(i)
time.sleep(1)
原理:
迭代器的产生过程,大致可以分为:
- 先构造一个可迭代对象,并且在
__iter__
的方法中返回另一个可迭代对象,并通过self
参数,传递给第二个可迭代对象自身的属性 - 另外的可迭代对象拥有一个
__next__
方法来构造一个迭代器 - 我们就可以对第一个可迭代对象使用
for
循环进行遍历
运行结果:
判断classmate_interator是否是迭代器: True
张三
李四
从输出结果也可以看出,我们成功的构造出了一个迭代器,并且通过for
循环取除了names
的值。
(2)第二种方法:
在第一种方法中,我们构造了两个可迭代对象来完成,构造迭代器。
其实,这里我们只需要将第一个迭代器的返回值设置为本身,并为自己添加__next__
方法,同样可以完成构造迭代器
实例:
from collections import Iterator
import time
class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
# 如果想要对象成为一个 可迭代对象(可以使用for),那么必须实现__iter__方法
return self
def __next__(self):
# 保证列表索引不越界的情况下,挨个返回列表names的内容
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
# 在遍历取值为None时,停止遍历
raise StopIteration
classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
classmate_interator = iter(classmate)
print('判断classmate_interator是否是迭代器:', isinstance(classmate_interator, Iterator))
for i in classmate:
print(i)
time.sleep(1)
运行结果:
判断classmate_interator是否是迭代器: True
张三
李四
可以看到,我们同样生成了迭代器,并且通过遍历获取值
3、迭代器的应用
我们发现迭代器最核心的功能是通过next()
函数的调用来返回下一个数据值,如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的,那么也就意味着可以不用再依赖一个已有的数据集合,也就是不用再将所有要迭代的数据都一次性缓存下来供后续读取,这样就可以节省大量的存储(内存)空间。
举例:
举个例子,比如,数学中有个著名的斐波那契数列(Fibonacci),数列中第一个数为0第二个数为1其后的每一个数都可由前面两个数相加得到:
0,1,1,2,3,5,8,13,21,34
现在我们想要通过for ... in ...
循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以用迭代器来实现,每次迭代都通过数学计算来生成下一个数。
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)
运行结果:
0
1
1
2
3
5
8
13
21
34
从运行结果的生成速度来看,有了明显的提高。
4、并不是只有for循环能接受可迭代对象
除了for
循环能接受可迭代对象,list
,tuple
等也能接收。
比如:我们有一个list_num=[1,2,3]
的列表和tuple_num = (1,2,3)
的元组。
li = list(tuple_num)
print(li)
tp = tuple(list_num)
print(tp)
这里的list、tuple
不是简单的类型转换,而是内部已经封装好了遍历的方法,对可迭代对象进行迭代并保存到自身开辟的内存中。