Python | 深入理解循环和迭代

前言
循环,特别是for循环,是Python/ target=_blank class=infotextkey>Python中常见的语句,甚至于Guido van Rossum(Python创始人)在评论递归的时候说过在Python中“递归已死”,我想这句话的意思不是说在Python中不能用递归,而是说因为Python中的for循环语句足够强大,可以不考虑递归,而是用for循环实现原本用递归做的事情 。
本文就在以上两本书所述基础上,从更深入和综合的角度进行阐述,以便能更好地使用for循环 。
在实用for循环中,特别是初学者,会遇到很多坑,这里列举几个,看看你是否遇到过?
1、第二次无果
假设有一个数字组成的列表和一个生成器,生成器给出这些数字的平方:
>>> numbers = [1, 2, 3, 5, 7]>>> squares = (n**2 for n in numbers)
用tuple函数,将squares转化为元组 。
>>> tuple(squares)(1, 4, 9, 25, 49)
现在,又向计算这个生成器对象squares里面所有数字的和,观察一下,应该能看出来,其和是88,然而:
>>> sum(squares)0
这里计算结果为0,是Python的BUG吗?
2、检查无效
再用下面的方法得到那个生成器对象:
>>> numbers = [1, 2, 3, 5, 7]>>> squares = (n**2 for n in numbers)
如果检查9是否在squares生成器中,显然这是真的True 。但是同样的检查如果再做一遍,就不是这个结果了——不可重复,不科学?
>>> 9 in squaresTrue>>> 9 in squaresFalse3、解包
创建一个包含两个键值对的字典:
>>> counts = {'Apples': 2, 'oranges': 1}
用多变量的赋值语句对字典解包:
>>> x, y = counts
先猜一下,这样做会有什么结果?报错,还是两个变量分别引用了两个键值对——引用键值对,兼职不可能吧,除非将键值对包裹在字典里 。
但是,一没有报错,二没有返回键值对,而是:
'apples'
这似乎也合乎情理和逻辑 。
传统的for循环
【Python | 深入理解循环和迭代】温故而知新,先来回顾一下for循环 。
严格地说,Python中的for循环并不“传统”,或者说不符合众多语言中所继承的C语言风格的for循环 。
先看一看所谓的C语言风格的for循环,以JAVAScript为例:
var numbers = [1, 2, 3, 5, 7];for (var i = 0; i < numbers.length; i += 1) {print(numbers[i]) }
像人们熟知的JavaScript, C, C++, Java, php等很多编程语言的for循环,都是这个样子的,所以,不少人认为这样的才是真正的for循环 。
但是,Python盲从,而是特立独行地创造了自己的for循环 。它不是C语言风格的,而是Python风格的:
numbers = [1, 2, 3, 5, 7]for n in numbers:print(n)
与传统的C语言风格的for循环不同,Python的for循环不需要创建索引,不需要对索引变量进行初始化,不需要进行边界检查,也不需要让索引递增 。Python的for循环为我们完成了在numbers列表上循环的所有工作 。
因此,Python中虽有for循环,但并非传统的C风格,那么其工作原理亦与之不同 。
可迭代对象和序列
在Python中,可迭代对象就是可以用for来循环的东西 。
for item in some_iterable:print(item)
序列是一种非常常见的可迭代对象,例如列表、元组和字符串都是序列 。
>>> numbers = [1, 2, 3, 5, 7]>>> coordinates = (4, 5, 7)>>> words = "hello there"
序列是具有一组特定特征的可迭代对象,它们可以从0开始索引,并在比序列长度少一个元素的地方结束 。它们有长度,并且可以切片 。列表、元组、字符串和所有其他序列都是这样工作的 。
>>> numbers[0]1>>> coordinates[2]7>>> words[4]'o'
Python中的很多东西都是可迭代对象,但并非所有的可迭代对象都是序列 。集合、字典、文件和生成器都是可迭代对象,但它们都不是序列 。
>>> my_set = {1, 2, 3}>>> my_dict = {'k1': 'v1', 'k2': 'v2'}>>> my_File = open('some_file.txt')>>> squares = (n**2 for n in my_set)
因此,任何可以用for来循环的东西都是一个可迭代对象,例如序列,但是并非所有可迭代对象都是序列 。
Python的for循环
前面已经显示了,Python的for循环不使用索引——这是不同于C语言分割的for循环之处 。
不过,你可能会悄悄滴认为,如果非要用,Python的for循环肯定也能实现C语言风格,因为我们一向认为“C语言是任何东西的基础” 。为此,我们使用while 循环和索引手动遍历一个可迭代对象:


推荐阅读