for 循环
for 用来把同一段代码重复执行。列表、字符串、字典、range 都可以交给它逐个处理。
Python 用缩进表示代码块,相当于其他语言的 {}。for 那一行以冒号结尾,下面缩进的几行才是循环体。
为什么需要循环
三个名字要各打印一次,可以写成三行:
print("tom")
print("jerry")
print("spike")
名字变成三十个,就要复制三十行。人会抄错,以后改格式还得改三十处。
循环只写一遍“拿到一个,就打印一个”,数据放在列表里,个数变了也不用改循环本身:
names = ["tom", "jerry", "spike"]
for name in names:
print(name)
tom
jerry
spike
for name in names 的意思是:按顺序从 names 里取出每一个值,临时叫 name,然后执行缩进的代码。取完就停。
缩进决定循环体
l1 = ["a", "b", "c"]
for i in l1:
print(i)
print("结束")
a
b
c
结束
print(i) 缩进了,所以打印三次。print("结束") 和 for 对齐,循环结束后只执行一次。
同一层要缩进同样多,推荐每层 4 个空格。少缩进、多缩进,或者空格和 Tab 混用,都会报 IndentationError。
循环体不能空着。暂时什么都不做,写 pass:
for i in l1:
pass
字符串也会被逐个取出
for 不限于列表。字符串会按字符走:
for ch in "hi":
print(ch)
h
i
元组和列表一样,按元素走。字典的遍历上一节 字典 已经写过,最常用的是 for k, v in d.items()。
固定次数
次数事先知道,就配合 range。下面把列表按下标再走一遍:
l2 = ["2", "a", 1, "d"]
for i in range(0, 4):
print(l2[i])
2
a
1
d
range(0, 4) 给出 0、1、2、3,正好是 l2 的合法下标。列表长度会变时,不要把 4 写死,用 range(len(l2))。
只是为了拿到元素时,直接遍历更短,也不用担心下标越界:
for item in l2:
print(item)
2
a
1
d
下标和值一起拿:enumerate
既要位置又要元素,用 enumerate。它是内置函数,不是一种新语法。括号和 print(...)、len(...) 一样,表示在调用函数。
for i, item in ... 里的逗号才是语法:函数每次交出两个东西,这里把它们拆开,前一个叫 i,后一个叫 item。
for i, item in enumerate(l2):
print(i, item)
0 2
1 a
2 1
3 d
直接打印函数的返回值,看到的不是列表,而是一个 enumerate 对象。要一次看完全部结果,用 list() 包一层。每一项是一个元组,里面是下标和元素:
print(type(enumerate(l2)))
print(list(enumerate(["a", "b"])))
<class 'enumerate'>
[(0, 'a'), (1, 'b')]
学习时用 list() 看结果即可。正式写循环时直接 for i, item in enumerate(...),不必先转成列表。
括号里能放什么
第一个参数要能被 for 逐个取出。列表、字符串、元组、range、字典都可以。单独一个数字不行。
字符串按字符编号:
for i, ch in enumerate("hi"):
print(i, ch)
0 h
1 i
元组、range 也一样,编号从 0 开始,跟元素自己的值无关:
for i, n in enumerate((10, 20)):
print(i, n)
for i, n in enumerate(range(3, 6)):
print(i, n)
0 10
1 20
0 3
1 4
2 5
range(3, 6) 产出的是 3、4、5。enumerate 另起一套编号 0、1、2,所以第一行是 0 3,不是 3 3。
字典放进去时,取出来的是 key,不是 value。编号表示这是第几个 key:
score = {"Jike": 90, "Anna": 85}
for i, name in enumerate(score):
print(i, name, score[name])
0 Jike 90
1 Anna 85
要 key 和 value 一起走,仍用上一节的 for name, value in score.items()。enumerate 并不取代它。
整数没有“下一个元素”,传进去会报错:
print(enumerate(5))
TypeError: 'int' object is not iterable
集合虽然也能放进 enumerate,但集合没有固定的位置顺序,编出来的号不能当成列表下标用。
第二个参数 start 可以不写,用来指定编号从几开始,必须是整数。它只改变打印出来的编号,不改变列表里的真实下标。
for i, item in enumerate(l2, start=1):
print(i, item)
1 2
2 a
3 1
4 d
在循环里累加
循环外面先准备一个变量,循环里面不断更新它。求三个数的和:
total = 0
for n in [10, 20, 30]:
total = total + n
print(total)
60
total 必须写在循环外面。写在里面的话,每转一圈都会重新变成 0,前面加上的数就丢了。
total = total + n 也可以写成 total += n,两个写法一样。
循环里面再套循环
外层每走一步,内层都要完整走一遍。
for i in range(1, 3):
for j in range(1, 3):
print(i, j)
1 1
1 2
2 1
2 2
i 先取 1,这时 j 取 1 再取 2。然后 i 变成 2,j 再取 1 和 2。内层缩进比外层多一层。
break 和 continue
有时不必走完。break 立刻结束整个循环,continue 跳过这一圈剩下的代码,直接进入下一圈。
这里用到了 if:条件成立才执行它下面的语句。if 的规则下一节再细讲。
for n in [1, 2, 3, 4, 5]:
if n == 3:
break
print(n)
1
2
遇到 3 就停,4 和 5 不会再打印。
for n in [1, 2, 3, 4, 5]:
if n == 3:
continue
print(n)
1
2
4
5
3 被跳过了,循环还在,所以 4 和 5 仍会打印。
for 也可以带 else
else 写在整个 for 后面,和循环对齐。它在循环没有被 break 打断时执行。
for n in [1, 3, 5]:
if n % 2 == 0:
print("找到偶数", n)
break
else:
print("全是奇数")
全是奇数
三个数里没有偶数,break 没执行,所以走到 else。
for n in [1, 4, 5]:
if n % 2 == 0:
print("找到偶数", n)
break
else:
print("全是奇数")
找到偶数 4
4 触发了 break,else 就不执行。这个 else 表示“没被打断”,不是“循环一次都没跑”。
while:条件成立就继续
for 适合“这一串东西,逐个处理”或者“次数已经知道”。还不知道要转几圈、只知道停下来的条件时,用 while。
n = 3
while n > 0:
print(n)
n = n - 1
print("停")
3
2
1
停
每次先看 n > 0 还成不成立。成立就执行循环体。这里每圈都把 n 减 1,减到 0 时条件不再成立,循环结束,然后打印“停”。
如果忘记写 n = n - 1,n 一直是 3,条件永远成立,程序就停不下来。这种循环叫死循环。终端里可以按 Ctrl + C 把它打断。
常见坑
循环变量在循环结束后还在。 它保留的是最后一圈的值。
for i in range(3):
print(i)
print("最后", i)
0
1
2
最后 2
空序列一次都没进循环体时,这个变量不会被赋值,后面使用它会报 NameError。
遍历列表时不要同时删元素。 删除会让后面的元素往前移,循环仍按原来的步伐走,于是跳过一个。
nums = [2, 4, 6]
for n in nums:
nums.remove(n)
print(nums)
[4]
三个偶数本来都想删掉,结果留下了 4。要删除时,先另做一个新列表,或者遍历 nums[:] 这份副本。
小结
- 冒号加缩进就是循环体,和
for对齐的代码只在循环结束后执行一次 - 遍历列表、字符串,直接
for item in ... enumerate是内置函数。括号里放列表、字符串、元组、range、字典这类能被for取出的对象,用来同时拿到编号和元素- 累加用的变量要放在循环外面
break结束整个循环,continue跳过本圈for的else在没有break时执行- 次数未知、只知道停止条件时用
while,记得让条件有机会变成不成立
下一节学习 if 判断。用 python examples/for.py 运行本节的例子。