for 循环语句普遍存在多种常见的高级编程语言,在 Python 中地位尤为重要,何以见得?学然后即知。
很多编程语言都继承了 C 语言的 for 循环风格,例如 JavaScript 中这样实现(以下代码不需调试):
var numbers = [1, 2, 3, 5, 7];
for (var i = 0; i < numbers.length; i += 1) {
print(numbers[i]) }
像这样的还有 Java、PHP 等编程语言。如果把这种类型的称为“传统”风格的话,Python 中的 for 循环则显得特立独行,它不是 C 语言风格的,它是 Python 风格的——别具一格。
numbers = [1, 2, 3, 5, 7]
for n in numbers: # (1)
print(n)
比较以上两段代码,后者是 Python 风格的 for 循环语句,与“传统”风格相比:
var i = 0 ;i < numbers.length ;i += 1 。Python 的 for 循环不仅形式上与 C 语言风格的不同,工作原理也不同,但下面还是先从形式上学习,原理内容留给以后探究。
下面以注释(1)为例,结合图6-3-1,说明 Python 的 for 循环基本用法:
for :发起 for 循环的关键词;n :引用被循环对象中成员的变量,注释(1)中的变量 n 依次引用列表中的每个成员;in :关键词,右侧的 numbers 变量引用了被循环对象。如果将 for n in numbers 看做自然语言中的一句话,其字面含义即意味着 n 引用 numbers 中的成员。

图6-3-1 for 循环语句结构
将注释(1)的循环语句在交互模式中执行,效果如下:
>>> numbers = [1, 2, 3, 5, 7]
>>> for n in numbers:
... print(n)
...
1
2
3
5
7
在 Python 中,只有可迭代对象才能够作为 for 循环语句中的被循环对象。关于可迭代对象,在第4章和第5章都有所介绍,第9章9.6节还会详细说明。
相传,高斯9岁时就证明了快速计算等差数列求和的技巧,即 1+2+3+\cdots+99+100 。这里我们用 Python 程序计算,并向大师致敬。
#coding:utf-8
'''
filename: sumhundred.py
'''
sum = 0
for i in range(1, 101): # (2)
sum += i # (3)
print(f"the sum of 1 to 100 is: {sum}")
先看执行效果,再分析程序中的重点代码:
% python sumhundred.py
the sum of 1 to 100 is: 5050
此结果与高斯计算的结果相同——是不是充满了成就感。不过,此处的方法和高斯的明显不同,高斯使用了等差数列求和公式,这里是逐个做加法——方法虽笨,但有计算机这个好工具,所以速度很快。下面就分解这个“笨方法”,理解每一部分含义:
range() 是 Python 的内置函数,它的调用方式是 rang(stop) 或者 range(start, stop[, step]) ,参数均为整数,生成由整数组成的等差数列——返回的对象不是列表,是 range 类型对象,这种类型的对象是一种“类列表”的序列,可以用 list() 函数将其转换为列表。
>>> range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 20, 2))
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
>>> 9 in range(10)
True
注释(2)中以 range(1, 101) 得到了由整数 1,2,\cdots, 100 作为成员的 range 对象,它是可迭代的,用于 for 循环。
变量 i 依次引用 range(1, 101) 中的每个整数,通过注释(3)实现“自增”计算(见6.1.1节),即完成 1+2+3+\cdots+99+100 计算。
利用 range() 函数,可以解决一些与等差数列有关的问题。例如,要求选出 50 以内能被 3 整除的非负整数,可以这样实现:
#coding:utf-8
"""
filename: divisibility.py
"""
lst = []
for i in range(50):
if i % 3 == 0:
lst.append(i)
print(f"numbers divisible by 3: {lst}")
执行结果是:
% python divisibility.py
numbers divisible by 3: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48]
其实,如果读者认真阅读 range() 官方文档,还会找到另外一种更直接的方法:
>>> list(range(0, 50, 3))
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48]
在慨叹其简洁之余,更要认识到阅读官方文档的重要性。
再来看一个将字符串作为 for 循环的示例。在这个示例中,要统计一个单词中每个字母的出现次数。
#coding:utf-8
'''
filename: countchar.py
'''
word = input('please input an english word:')
result = {} # (4)
for e in word: # (5)
if e in result: # (6)
result[e] += 1
else:
result[e] = 1
print(f'the word is: {word}')
print(f'count letter: {result}')
先看执行结果,再分析代码。
% python countletter.py
please input an english word:zoom
the word is: zoom
count letter: {'z': 1, 'o': 2, 'm': 1}
按照“用户的输入都不可信”原则,上述程序还有待优化。但是,这里我们要将注意力放在 for 循环语句,姑且认为“人之初,性本善”的假设是成立的。
要统计单词中每个字母出现的次数,显然要建立字母与出现次数的对应关系——立刻想到了“键值对”,最适合的就是用字典类型的对象保存统计结果,于是注释(4)创建一个空字典。
注释(5)循环单词(字符串对象)中的每个成员——字母,然后在循环体(注释(6)开始的语句块)内,判断该字母是否已经是 result 的键:如果是,说明此前已经对该字母计数,所以让它对应的值“自增” 1 ;否则,在 result 中增加一个以该字母为键的键值对,并设置初始的值为 1 。
这样,就实现了记录对象出现次数的统计,这种方法在后续示例中还会用到。
列表和字符串都是序列,也都是可迭代对象,此外,字典虽然不是序列,但是可迭代对象,故也可以作为 for 循环语句中的被循环对象。
>>> d = dict([("website", "www.itdiffer.com"), ("lang", "python"), ("author", "laoqi")])
>>> for k in d: print(k) # (7)
...
website
lang
author
注释(7)是一种“偷懒”的写法,在冒号 : 后面跟一个空格,然后写循环体的语句。这种写法仅适用于循环体的语句块中只有一条语句的情况。当然,将 print(t) 写在下一行(前面有四个空格)依然可行,且效果相同。
从代码的运行结果可知,注释(7)中的变量 k 依次引用了字典 d 的键值对的键(key)。
>>> for k in d.keys(): print(k)
...
website
lang
author
这段代码中使用了字典的方法 keys() (参阅第5章5.1.3节),与注释(7)等效,不过常用的还是注释(7)。
若要通过循环得到键值对中的值(value),不难想到字典的另外一个方法 values() 。
>>> for v in d.values(): print(v)
...
www.itdiffer.com
python
laoqi
自然还会想到字典的 items() 方法返回值也可以用于被循环对象,但是要注意,d.items() 返回值有点特别。
>>> d.items()
dict_items([('website', 'www.itdiffer.com'), ('lang', 'python'), ('author', 'laoqi')])
循环此种形式的对象,得到每组键值对的键和值:
>>> for k, v in d.items(): # (8)
... print(f'key:{k} --> value:{v}')
...
key:website --> value:www.itdiffer.com
key:lang --> value:python
key:author --> value:laoqi
注释(8)中 (k, v) 与 d.items() 返回值的每个成员依次循环对应引用,即 k 引用键值对的键,v 引用键值对的值。
此外,用注释(7)的循环方式,也能实现注释(8)的结果:
>>> for k in d:
... print(f'key:{k} --> value:{d[k]}')
...
key:website --> value:www.itdiffer.com
key:lang --> value:python
key:author --> value:laoqi
以上初步了解了 for 循环的基本应用。为了让 for 循环用得更妙,Python 中的两个内置函数必须要了解。