Python while和for循环

Python while和for循环

本篇讲解Python的两个主要循环结构:也就是不停重复代码操作的语句。
首先是while语句,提供编写通用循环的一种方法;
第二种是for语句,用来遍历序列对象内的元素,并对每一个元素执行一个代码块。

while循环

while语句是Python语言中最通用的迭代结构。根据顶端测试判断的真假值,选择是否重复执行一个语句块(缩进代码)。

while一般格式

首行测试表达式,有一行或多行缩进语句的主体以及一个可选的else部分(warning:控制权离开循环而又没有碰到break语句是执行else部分)。

1
2
3
4
while <test>:
<statements1>
else:
<statements2>

举例介绍:

  1. 此例判断条件永远是真,所以print函数一直执行;
1
2
while True:
print('Type Ctrl-C to stop me!')
  1. 此例不停截取字符串,判断是否为空;
1
2
3
4
x = 'minikui'
while x:
print(x, end=' ')
x = x[1:]
  1. 此例是比较常见的计数循环,从0一直数到10;
1
2
3
4
a = 0; b = 10
while a < b:
print(a, end=' ')
a += 1

Python并没有do while语句,可以在循环主体语句底部以一个测试和break模拟实现。

break, continue, pass和循环else

breakcontinue只有嵌套在循环中才起作用。

  • break:
    跳出最近所在的循环,跳出整个循环;
  • continue:
    • 跳出本次循环,跳至循环开头,继续下一次循环;
  • pass:
    • 什么也不做,空占位语句;
  • 循环else块:
    • 只有循环正常离开的时候才执行else

一般循环格式

加入break和continue语句以后,while的一般格式:

1
2
3
4
5
6
while <test1>:
<statements1>
if <test2>: break
if <test3>: continue
else:
<statements2>
  • pass

pass语句是不执行代码的占位语句,可以在以后填充操作代码。

在 Python 3中,可以在使用表达式的任何地方使用”…”来省略代码,pass的一种替代。

  • continue

continue语句跳至循环顶端的测试。举例如下:

1
2
3
4
5
x = 10
while x:
x -= 1
if x % 2 != 0: continue
print(x, end=' ')
  • break

break语句立刻离开循环体,结束循环。碰到break时,之后的循环代码都不执行。举例如下:

1
2
3
4
5
while True:
name = input('Enter name:')
if name == 'stop': break
age = input('Enter age:')
print('Hello', name, '=>', int(age) ** 2)
  • 循环else

通常结合break使用的特殊情况:

1
2
3
4
5
6
7
8
x = y // 2
while x > 1:
if y % x == 0:
print(y, 'has factor', x)
break // 遇到break,直接无视else部分
x -= 1
else:
print(y, 'is prime')

若是循环主体部分没有执行,循环else分句也执行。

more about else

else分句是Python特有的。举例“搜索列表值”对比else的作用:

  • 不使用else分句:
1
2
3
4
5
6
7
8
9
found = False
while x and not found:
if match(x[0]):
print('Ni')
found = True
else:
x = x[1:]
if not found:
print('not found')
  • 使用else分句:
1
2
3
4
5
6
7
while x:
if match(x[0])
print('Ni')
break
x = x[1:]
else:
print('not found')

Python 应该是表达式出现的场合,不能出现赋值语句。

for循环

for循环在Python中是一个通用的序列迭代器:可以遍历任何有序的序列对象内的元素。可用于字符串、列表、元组、其他内置可迭代对象以及之后我们使用类创建的对象。

一般格式

for循环首行定义了一个赋值目标,以及你想遍历的对象。后面是你想重复的语句块。

1
2
3
4
for <target> in <object>:
<statements>
else:
<statements>

Python执行for循环的时候,逐个将序列对象中的元素赋值给目标,然后为每个元素执行循环主体。主体一般使用赋值的目标引用序列中的元素,像是序列的游标。

加入break和continue以后:

1
2
3
4
5
6
for <target> in <object>:
<statements>
if <test>: break
if <test>: continue
else:
<statements>
  • 基本应用
    for循环遍历任何一种序列对象。
1
2
prod = 1
for i in [1, 2, 3, 4]: prod *= i
  • 其他数据类型
    任何序列都适用for循环,例如字符串和元组。
1
2
3
4
S = 'minikui'
T = ('name', 'age', 18)
for x in S: print(x, end=' ')
for x in T: print(x, end=' ')

for循环甚至可以应用到一些不是序列的对象上,比如字典和文件。

  • for循环中的元组赋值
    元组解包赋值的一个例子。
1
2
3
T = [(1, 2), (3, 4), (5, 6)]
for (a, b) in T:
print(a, b)

循环中的元组赋值使得使用items方法来遍历字典中的键和值更方便,不必再遍历键索引获取值:

1
2
3
4
5
6
7
D = {'name' : 'minikui', 'age' : 18}
for key in D:
print(key, '=>', D[key])
list(D.items())
for (key, value) in D.items():
print(key, '=>', value)

for循环的元组解包赋值只是元组赋值的一种实现,并不特殊。
即使嵌套的:

for ((a, b), c) in [((1, 2), 3), ((4, 5), 6)]: print(a, b, c)

Python 3在for循环中扩展的序列赋值

主要体现是Python 3的扩展序列解包赋值。

1
2
for (a, *b, c) in [(1, 2, 3, 4), (5, 6, 7, 8)]:
print(a, b, c)

嵌套for循环

代码在对象列表中搜索每个键,匹配搜索:

1
2
3
4
5
6
7
8
9
10
items = ['name', 18, (1, 2), 11.0]
tests = [(1, 2), 1.1]
for key in tests:
for item in items:
if item == key:
print(key, 'was found')
break
else:
print(key, 'not found')

使用in成员测试编写:

1
2
3
4
5
for key in tests:
if key in items:
print(key, 'was found')
else:
print(key, 'not found')

用for循环做集合交集处理:

1
2
3
4
5
6
7
seq1 = 'minikui'
seq2 = 'kui'
res = []
for x in seq1:
if x in seq2:
res.append(x)

编写循环的技巧

for循环包括多数计数器式的循环。for比while要更容易编写,执行也比较快。
Python提供了两个内置函数,在for循环内定制迭代:

  • 内置range()函数返回一系列连续增加的整数,可作for中索引;
  • 内置zip()函数返回并行元素的元组的列表,可在for内遍历数个列表;

循环计数器:while和range

在Python 3种,range是一个迭代器,根据需要产生元素。使用range的时候,更多的是使用索引来操作序列内元素,for循环本身处理了迭代的细节,不需要使用range

建议:尽可能多选择for,而不要使用range。

非完全遍历:range和切片

在循环的时候,想要避开一些值,可以使用range和切片实现:

1
2
3
4
5
6
7
// range
S = 'minikui'
list(range(0, len(S), 2))
for i in range(0, len(S), 2): print(S[i], end=' ')
// 切片
for c in S[::2]: print(c, end=' ')

for循环修改列表:range()

一般情况:

1
2
3
4
L = [1, 2, 3, 4, 5]
for x in L:
x += 1
// L = [1, 2, 3, 4, 5], x = 6

这里修改的是变量x,而不是列表L。想要修改列表L,需要使用索引。

1
2
3
4
L = [1, 2, 3, 4, 5]
for i in range(len(L)):
L[i] += 1
// L = [2, 3, 4, 5, 6]

并行遍历:zip和map

内置zip函数让我们使用for循环来并行使用多个序列。zip取得一个或多个序列为参数,返回元组的列表,将这些序列中的并排的元素配成对。

1
2
3
4
5
6
7
8
L1 = [1, 2, 3, 4]
L2 = [5, 6, 7, 8]
// 要合并列表中的元素,可以使用zip创建一个元组对列表(Python 3中,zip也是一个可迭代对象)。
zip(L1, L2)
// 从两列表中提取出来的元素配对。
for (x, y) in zip(L1, L2):
print(x, y, '--', x+y)

zip可以接受任何类型的序列(任何可迭代对象,包括文件)。可接受3个参数,参数长度不同时,zip以最短序列的长度截取所得到的元组。

  • zip构造字典
1
2
3
4
5
6
7
8
keys = []
values = []
zip(keys, values)
for (k, v) in zip(keys, values): D[k] = v
// 直接传给dict
D = dict(zip(keys, values))

Python 2中的map等价形式

类似zip配对序列的元素,只是长度不同时,较短的序列用None补齐。

Python 3不再支持此种用途的map,map是Python 3中的一个值生成器。

map带有一个函数,以及一个或多个序列参数,用从序列中取出来的并行元素调用函数。
list(map(ord, 'minikui'))

产生偏移和元素:emumerate

1
2
3
S = 'minikui'
for (offset, item) in enumerate(S):
print(item, 'appears at offset', offset)

enumerate函数返回一个生成器对象,支持迭代协议。既是对象有一个__next__方法,由next()内置函数调用,并且循环中每次迭代的时候都返回一个(index, value)的元组。

1
2
3
4
5
n = enumerate(S)
next(n) // 不停调用
[c * i for (i, c) in enumerate(S)]