numbers = [1, 2, 3, 5, 7]i = 0while i < len(numbers):print(numbers[i])i += 1这适用于列表,但它不会对所有东西都起作用 。这种循环方式只适用于序列 。
如果我们尝试用索引去手动遍历一个集合,我们会得到一个错误:
>>> fruits = {'lemon', 'apple', 'orange', 'watermelon'}>>> i = 0>>> while i < len(fruits):... print(fruits[i])... i += 1...Traceback (most recent call last):File "<stdin>", line 2, in <module>TypeError: 'set' object does not support indexing集合不是序列,所以它们不支持索引 。
我们不能使用索引手动对 Python 中的每一个迭代对象进行遍历 。对于那些不是序列的迭代器来说,这是行不通的 。
迭代器驱动 for 循环
因此,我们已经看到,Python 的 for 循环在底层不使用索引 。相反,Python 的 for 循环使用迭代器 。
迭代器就是可以驱动可迭代对象的东西 。你可以从任何可迭代对象中获得迭代器,你也可以使用迭代器来手动对它的迭代进行遍历 。
让我们来看看它是如何工作的 。
这里有三个可迭代对象:一个集合,一个元组和一个字符串 。
>>> numbers = {1, 2, 3, 5, 7}>>> coordinates = (4, 5, 7)>>> words = "hello there"我们可以使用 Python 的内置 iter 函数来访问这些迭代器,将一个迭代器传递给 iter 函数总会给我们返回一个迭代器,无论我们正在使用哪种类型的迭代器 。
>>> iter(numbers)<set_iterator object at 0x7f2b9271c860>>>> iter(coordinates)<tuple_iterator object at 0x7f2b9271ce80>>>> iter(words)<str_iterator object at 0x7f2b9271c860>一旦我们有了迭代器,我们可以做的事情就是通过将它传递给内置的 next 函数来获取它的下一项 。
>>> numbers = [1, 2, 3]>>> my_iterator = iter(numbers)>>> next(my_iterator)1>>> next(my_iterator)2迭代器是有状态的,这意味着一旦你从它们中消耗了一项,它就消失了 。
如果你从迭代器中请求 next 项,但是其中没有更多的项了,你将得到一个 StopIteration异常:
>>> next(my_iterator)3>>> next(my_iterator)Traceback (most recent call last):File "<stdin>", line 1, in <module>StopIteration所以你可以从每个迭代中获得一个迭代器,迭代器唯一能做的事情就是用 next 函数请求它们的下一项 。如果你将它们传递给 ext,但它们没有下一项了,那么就会引发 StopIteration 异常 。
你可以将迭代器想象成 Pez 分配器(LCTT 译注:Pez 是一个结合玩具的独特复合式糖果),不能重新分配 。你可以把 Pez 拿出去,但是一旦 Pez 被移走,它就不能被放回去,一旦分配器空了,它就没用了 。
没有 for 的循环
既然我们已经了解了迭代器和 iter 以及 next 函数,我们将尝试在不使用 for 循环的情况下手动遍历迭代器 。
我们将通过尝试将这个 for 循环变为 while 循环:
def funky_for_loop(iterable, action_to_do):for item in iterable:action_to_do(item)为了做到这点,我们需要:
从给定的可迭代对象中获得迭代器
【python中的for循环在底层是如何开展工作的?】反复从迭代器中获得下一项
如果我们成功获得下一项,就执行 for 循环的主体
如果我们在获得下一项时得到了一个 StopIteration 异常,那么就停止循环
def funky_for_loop(iterable, action_to_do):iterator = iter(iterable)done_looping = Falsewhile not done_looping:try:item = next(iterator)except StopIteration:done_looping = Trueelse:action_to_do(item)我们只是通过使用 while 循环和迭代器重新定义了 for 循环 。
上面的代码基本上定义了 Python 在底层循环的工作方式 。如果你理解内置的 iter 和 next函数的遍历循环的工作方式,那么你就会理解 Python 的 for 循环是如何工作的 。
事实上,你不仅仅会理解 for 循环在 Python 中是如何工作的,所有形式的遍历一个可迭代对象都是这样工作的 。
迭代器协议iterator protocol 是一种很好表示 “在 Python 中遍历迭代器是如何工作的”的方式 。它本质上是对 iter 和 ext 函数在 Python 中是如何工作的定义 。Python 中所有形式的迭代都是由迭代器协议驱动的 。
迭代器协议被 for 循环使用(正如我们已经看到的那样):
for n in numbers:print(n)多重赋值也使用迭代器协议:
x, y, z = coordinates星型表达式也是用迭代器协议:
a, b, *rest = numbersprint(*numbers)许多内置函数依赖于迭代器协议:
推荐阅读
- 茶叶市场营销策略中的茶文化营销
- 苏麻喇姑嫁给康熙皇帝了吗 康熙王朝中的苏麻喇姑嫁给康熙了吗
- python多线程爬取youtube视频,外面的世界很精彩
- python爬取拉勾网数据并进行数据可视化
- 淮阴侯列传中的韩信是一个怎样的人
- Python匿名函数的介绍及用途
- Python教程:使用Turtles画出带有花瓣的花
- 9道国宴中的巅峰中国菜 中国国宴菜单
- 对人伸出中指,其中的意思 竖中指是什么意思
- iOS 14中的5个隐藏功能