for 循环的底层逻辑
先来看下面这段代码:
lst = [1,2,3,4,5]
for i in lst:
print(i)
for...in...
这个结构后面跟的 lst 一定是一个可迭代的对象,那可迭代对象有哪些呢:
print(issubclass(list,Iterable))
print(issubclass(dict,Iterable))
print(issubclass(str,Iterable))
print(issubclass(tuple,Iterable))
print(issubclass(int,Iterable))
可以看出,可迭代对象(Iterable)有:
- 字典
- 列表
- 字符串
- 元组
- 集合
那么让我们继续回到 for 循环来看
当执行了 for
循环的语句之后,会调用 iter()
方法,将可迭代对象(in 后面的内容) 转化成一个迭代器对象,然后调用 迭代器对象中的 next()
方法,将迭代器中的对象一个个的顺序输出,如下图代码中所示的对比效果:
lst = [1,2,3,4,5]
for i in lst:
print(i)
lst1 = [1,2,3,4,5]
iterator = iter(lst1) # 将可迭代对象lst1 转换成迭代器对象 iterator
while iterator:
try:
print(next(iterator)) # 当 iterator 不为空的时候,使用next() 方法不断打印其中的值
except StopIteration: # 当next() 到最后一个元素的时候会抛出异常 StopIteration,我们捕捉这个异常,并且退出循环;以此完成了for循环同样的效果
break
其实这整个过程分成了两步:
- lst1是一个容器,这个容器中通过开辟内存而存放了 1, 2, 3,4, 5 这些元素
- 将容器中赋予
__iter__
这个方法,这个容器才能够呈现出把每个元素进行操作的功能
所以,我们拿掉列表的容器功能,不让他存储数据,那么他不就变成了一个简单的可迭代对象了么~
但是!!!!如果没有给这个类中加入__next__
方法,是不可以对其进行 iter() 而变成迭代器对象的。
class MyList:
def __init__(self):
self.value = 1
def __iter__(self):
return self
lst = MyList()
print(isinstance(lst, Iterable))
lst = iter(lst)
print(isinstance(lst,Iterator))
我们还可以把 next 方法加进去,然后对这个可迭代的对象进行 iter() 操作,使他变成一个迭代器对象,例如:
class MyList:
def __init__(self):
self.value = 1
def __iter__(self):
return self
def __next__(self):
pass
lst = MyList()
print(isinstance(lst, Iterable))
lst = iter(lst)
print(isinstance(lst,Iterator))
所以我们可以得到很浅显的结论:
- 一个对象可不可迭代(Iterable)决定了能不能对其使用 for 循环
- 一个对象是不是迭代器对象(Iterator)决定了能不能单独那他来进行功能实现。
- 使用 Iterable 的性质,只有放在容器里才有意义,没有容器的功能,只有可迭代的性质是毫无用处的。但是 iterator 不需要自身有容器就可以完成很多功能。
直接这么说可能不够直观,我们通过下面的例子来写个功能来看一下~
- 现在我要用两个可迭代对象 lst1 和 lst2 和他们的容器功能来生成一个斐波那契数列
- 我也可以用一个迭代器直接生成斐波那契数列,而不需要占用额外的内存空间
方法一:使用可迭代对象 + 容器 来完成斐波那契数列
lst = [0,1]
for i in range(10):
lst.append(lst[-1]+lst[-2])
print(lst[1:])
方法二:直接创建迭代器来完成斐波那契数列
class Feb:
def __init__(self,length): # length取决于用户想产生多长的斐波那契数列
self.a = 0 # a 和 b 是数列初始值
self.b = 1
self.length = length
def __iter__(self): # 自身就是可迭代的,所以这个函数返回自身即可
return self
def __next__(self): # 核心部分:如何处理每一个迭代的结果
while self.length > 0:
self.length -= 1
self.a, self.b = self.a + self.b, self.a
return self.a
if __name__ == '__main__':
s = Feb(8)
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))
当迭代器对象的所有元素输出后,剩下的就是 None了