序言
Python 中的 for 循环和其他措辞中的 for 循环事情办法是不一样的,本日就带你深入理解 Python 的 for 循环,看看它是如何事情的,以及它为什么按照这种办法事情。
循环中的陷阱

我们先来看一下 Python 循环中的「陷阱」,在我们理解了循环的事情办法后,再来看下这些陷阱到底是怎么涌现的。
陷阱 1:循环两次
现在我们先假设有一个数字组成的列表,和一个用于返回这些数字的平方的天生器:
>>> nums = [1, 2, 3, 4]>>> squares = (n2 for n in nums)
我们可以将这个天生器工具通报给元组布局器,从而可以得到一个元组:
>>> tuple(squares)(1, 4, 9, 16)
这个时候,如果我们再将这个布局器工具通报给 sum 函数,按理说该当会返回这些数字的和吧:
>>> sum(squares)0
返回的是个 0,先拖住下巴。
陷阱 2:检讨是否包含
我们还是利用上面的数字列表和天生器:
>>> nums = [1, 2, 3, 4]>>> squares = (n2 for n in nums)
如果我 squares 天生器中是否包含 9,答案是肯定的,若果我再问一次呢?
你敢答应吗
>>> 9 in squaresTrue>>> 9 in squaresFalse
创造,第二次不灵了~
怎么不灵了
陷阱 3:拆包
现在假设有一个字典:
>>> counts = {1:'a', 2:'b'}
然后,我们用多个变量对字典进行拆包:
>>> x,y = counts
你以为这时候,x 和 y 中会是什么?
>>> x1>>> y2
我们只得到了键。
下面,我们先来理解下 Python 中的循环事情事理,然后再反过分来看这些陷阱问题。
一些观点
首先,先理解一些基本观点:
可迭代和序列
可迭代便是指任意可以利用 for 循环遍历的东西,可迭代意味着可以遍历,任何可以遍历的东西都是可迭代的。
for item in some_iterable:print(item)
序列是一种常见的可迭代类型,如列表、元组、字符串等。
序列是可迭代的,它有着一些特点,它们是从 0 开始索引,索引长度不超过序列的长度;它们有序列长度;并且它们可以被切分。
Python 中的大部分东西都是可以迭代的,但是可以迭代并不虞味着它是序列。如凑集、字典、文件和天生器都是可迭代的,但是它们都不是序列。
>>> my_set = {1, 2, 3}>>> my_dict = {'k1': 'v1', 'k2': 'v2'}>>> my_file = open('some_file.txt')>>> squares = (n2 for n in my_set)
总结下来便是,任何可以用 for 循环遍历的东西都是可迭代的,序列可迭代的类型中的一种,Python 还有着许多其他种类的可迭代类型。
迭代器
迭代器便是可以驱动可迭代工具的东西。你可以从任何可迭代工具中得到迭代器,你也可以利用迭代器来手动对它的迭代进行遍历。
下面有三个可迭代工具:一个凑集、一个元祖和一个字符串:
>>> nums = {1,2,3,4}>>> coors = (4,5,6)>>> words = "hello hoxis"
我们可以利用 Python 的内置函数 iter ,从这些可迭代工具中获取到迭代器:
一旦我们有了迭代器,我们就可以利用其内置函数 next() 来获取它的下一个值:
若果迭代到头了,也便是没有下一个值了,就会抛出 StopIteration 非常。也便是说,它不会连续循环取获取第一个值。
是不是有点懵逼了?
可迭代工具是可以迭代的东西迭代工具器实际上是遍历可迭代工具的代理迭代器没有长度,它们不能被索引。可以利用迭代器来做的唯一有用的事情是将其通报给内置的 next 函数,或者对其进行循环遍历可以利用 list() 函数将迭代器转换为列表如果想再次将其转换为列表,明显地,得到的是一个空列表。
实在这也是迭代器的一个主要特性:惰性,只能利用一次,只能循环遍历一次。并且,在我们调用 next() 函数之前,它不会做任何事情。因此,我们可以创建无限长的迭代器,而创建无限长的列表则弗成,那样会耗尽你的内存!
可迭代工具不一定是迭代器,但是迭代器一定是可迭代的:
实在,Python 中有许多迭代器,天生器是迭代器,Python 的许多内置类型也是迭代器。例如,Python 的 enumerate 和 reversed 工具便是迭代器。zip, map 和 filter 也是迭代器;文件工具也是迭代器。
Python 中的 for 循环
实在,Python 并没有传统的 for 循环,什么是传统的 for 循环?
我们看下 Java 中的 for 循环:
这是一种 C风格 的 for 循环,JavaScript、C、C++、Java、PHP 和一大堆其他编程措辞都有这种风格的 for 循环,但是 Python 确实没有。
Python 中的我们称之为 for 循环的东西,确切的说该当是 foreach 循环:
numbers = [1, 2, 3, 5, 7]for n in numbers:print(n)
和 C风格 的 for 循环不同之处在于,Python 的 for 循环没有索引变量,没有索引变量的初始化,边界检讨和索引变量的增长。
这便是 Python 的 for 循环的不同之处!
利用索引?
你可能会疑惑,Python 的 for 循环是否在底层利用了索引,下面我们手动的利用 while 循环和索引来遍历:
对付列表,这样遍历是可以的,但不代表适用于所有可迭代工具,它只适用于序列。
比如,我们对一个 set 利用这种方法遍历,会得到一个非常:
由于 set 不是序列,因此不支持索引遍历。
我们不能利用索引手动对 Python 中的每一个迭代工具进行遍历。对付那些不是序列的迭代器来说,更是行不通的。
实现没有 for 的循环
从上文可以看出,Python 中的 for 循环不该用索引,它利用的是迭代器。让我们来看下它是如何事情的。
通过上文,我们理解到了迭代器和 iter、next 函数,现在我们可以考试测验不用 for 循环来遍历一个可迭代工具。
下面是一个正常的 for 循环:
def funky_for_loop(iterable, action_to_do):for item in iterable:action_to_do(item)
我们要考试测验用迭代器的方法和 while 实现上面 for 循环的逻辑,大致步骤如下:
获取给定可迭代工具的迭代器;调用迭代器的 next() 方法获取下一项;对当前项数据进行处理;如果捕获到 StopIteration ,那么就停滞循环Python 底层的循环事情办法基本上如上代码,便是迭代器驱动的 for 循环。
再次回到循环陷阱
陷阱 1:耗尽的迭代器
陷阱 1 中,由于天生器是迭代器,迭代器是惰性的,也是一次性的,在已经遍历过一次的情形下,再对其求和,返回的便是一个 0。
陷阱 2:部分花费迭代器
陷阱 2 中,我们两次讯问 9 是否存在于同一个天生器中,得到了不同的答案。
这是由于,第一次讯问时,Python 已经对这个天生器进行了遍历,也便是调用 next() 函数查找 9,找到后就会返回 True,第二次再讯问 9 是否存在时,会早年次的位置连续 next() 查找。
陷阱 3:拆包是迭代
当直接在字典上迭代时,得到的是键:
而对字典拆包时,和在字典上遍历是一样的,都是依赖于迭代器协议,因此得到的也是键。
总结
序列是迭代器,但是不是所有的迭代器都是序列。迭代器不可以被循环遍历两次、不能访问其长度,也不能利用索引。
迭代器是 Python 中最基本的可迭代形式。如果你想在代码中做一个惰性迭代,请考虑迭代器,并考虑利用天生器函数或天生器表达式。
请记住,Python 中的每一种迭代都依赖于迭代器协议,因此理解迭代器协议是理解 Python 中的循环的关键。
好了以上便是这篇文章的全部内容了,希望本文的内容对大家的学习或者事情具有一定的参考学习代价,如果有疑问大家可以留言互换.
结尾末了多说一句,小编是一名python开拓工程师,这里有我自己整理了一套最新的python系统学习教程,包括从根本的python脚本到web开拓、爬虫、数据剖析、数据可视化、机器学习等。想要这些资料的可以关注小编,并在后台私信小编:“07”即可领取。