0.本集概览
1.while循环和for循环的基本用法
2.几种容器对象(列表、字典、元组、字符串和文件)的遍历方法
3.range、zip、enumerate的循环高级技巧
4.列表解析式与字典解析式
循环是每个程序语言的最基本最重要的部分之一,这一部分我们来说说循环迭代这个话题。
大家肯定会说:循环就是for循环、while循环嘛。不过python的循环使用更方便,涉及的技巧和用法也更值得好好聊聊。
1.Python中的循环基本用法
现在就来谈谈循环的基本用法,通过这一节你就能愉快的使用python中常见的循环用法了。
1.1.while循环用法解析
首先是while循环。需要反复循环执行的部分(也就是循环主体)在顶端测试条件为真时会重复执行,直到测试条件变为假时退出。举个简单的例子一看就明白了,其中循环主体就是while后缩进的代码块。
代码片段:
a = 0
b = 10
while a < b:
print(a, end=' ')
a = a + 1
运行结果:
0 1 2 3 4 5 6 7 8 9
接着再介绍一下while循环中会用到的continue,break和else三个关键字
continue是跳出本轮循环,回到循环主体的顶部再次开始新的循环
代码片段:
a = 0
b = 10
while a < b:
a = a + 1
if a % 2 != 0:
continue
print(a, end=' ')
运行结果:
2 4 6 8 10
break是直接跳出循环
代码片段:
a = 0
b = 10
while a < b:
a = a + 1
if a == 5:
break
print(a, end=' ')
运行结果:
1 2 3 4
else关键字,只有当循环正常离开的时候才会执行,即没有碰到break语句
代码片段:
y = 33
x = y // 2
while x > 1:
if y % x == 0:
print('{} has a factor {}'.format(y,x))
break
x = x - 1
else:
print('{} is prime'.format(y))
运行结果:
33 has a factor 11
我们可以看出,如果y不是质数,就会执行到break语句,从而跳过else语句,不执行else语句
如果是一个质数,就不会运行到break语句,循环正常退出的话,就执行else语句
代码片段:
y = 29
x = y // 2
while x > 1:
if y % x == 0:
print('{} has a factor {}'.format(y,x))
break
x = x - 1
else:
print('{} is prime'.format(y))
运行结果:
29 is prime
1.2.for循环用法解析
我们再来看看for循环
**for循环更加通用,他是一个通用的序列迭代工具,可以遍历任何有序的序列对象内的元素。**例如:字符串、列表、元组等,以及其他一些内置的可以用来迭代的对象(这个内容到时候专门花章节展开)。
1.2.1.列表、字符串与元组的遍历
回顾几个例子:列表、字符串、元组的遍历
代码片段:
for x in [1,2,3,4]:
print(x, end=' ')
运行结果:
1 2 3 4
代码片段:
for x in 'hello':
print(x, end=' ')
运行结果:
h e l l o
代码片段:
for x in ('i', 'am', 'a', 'teacher'):
print(x,end=' ')
运行结果:
i am a teacher
代码片段:
T = [(1, 2), (3, 4), (5, 6)]
for (a, b) in T:
print(a,b)
运行结果:
1 2
3 4
5 6
这里再单独说说另外两种特殊的内置类型对象,一个是字典、一个是文件。
1.2.2.字典的遍历
字典的遍历这里单独说说,相比于上面几个序列类型,字典的特殊之处在于他内部的对象不是有序的。
但是他也能通过for循环来遍历,常见的是通过键来遍历,还有一种是通过键值对的元组来遍历
代码片段:
D = {'a':1, 'b':2, 'c':3}
for key in D:
print(key, '--->', D[key])
运行结果:
b ---> 2
c ---> 3
a ---> 1
代码片段:
D = {'a': 1, 'b': 2, 'c': 3}
for (key, value) in D.items():
print(key, '--->', value)
运行结果:
a ---> 1
c ---> 3
b ---> 2
1.2.3.文件的遍历
由于文件这个类型还没有单独讲解,大家可以先了解一下,文件的详细内容后续章节会专门分析。
因为文件保存了很多字符和行,因此也是循环常见的典型使用案例,最原始的方法可以调用文件对象的read方法,把文件内容一次性加载至字符串对象。
代码片段:
file = open('myfile.txt', 'r')
print(file.read())
运行结果:
hello text file
goodbyt text file
Hahahahah
那么如果想逐行读取文本文件呢?for循环是最易于编写及执行最快的选择,这里有两种方法,
代码片段:
for line in open ('myfile.txt','r').readlines():
print(line, end='')
for line in open ('myfile.txt','r'):
print(line, end='')
运行结果:
hello text file
goodbyt text file
Hahahahah
这两种方法的运行结果是一样的,表面差别不大,但实际上有很大的区别:
第一种方法通过readlines方法,会首先一次性把文件载入到行字符串列表中,然后再对这个字符串列表进行迭代;
而第二种方法运行的原理则有所不同,他并非一次性将全部的文件内容载入到内存中,而是在迭代的时候,循环到了哪一行才将哪一行读入到内存。这里涉及到一个新的概念----迭代器(open函数返回的那个就是文件迭代器),后面再着重系统介绍。
现在我们只需要知道,第二种方法是文本文件读取的最佳选择,它简单、且对任意大小的文件都有效,因为他不会一次性把整个文件都载入到内存中,相反第一种方法存在内存压力过大的问题。
所以综上看来,for比while循环容易编写,执行时也比较快。
所以每当你需要遍历序列时,都应该将其作为首选的工具,同时还应该熟练使用一些循环迭代的技巧来优化你的程序,那么接着,我们说说三种循环迭代的常用技巧。
2.循环迭代的高级技巧
下面我们来讲讲三种循环迭代的常用技巧,range、zip和enumerate
2.1.range的使用方法
内置函数range:用来返回一系列连续增加的整数。这个函数产生的连续增加的整数序列,可以作为for循环迭代的索引
代码片段:
for x in range(5):
print(x, end=',')
运行结果:
0,1,2,3,4,
range也可以用在任何需要整数列表的地方。直接打印range函数的返回值是不能直接返回一个整数列表的,如果将其作为一个参数传给list函数,则可以一次性显示全部结果。
代码片段:
print(range(5))
运行结果:
range(0, 5)
代码片段:
print(list(range(-5,5)))
运行结果:
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
内置函数range在for循环中是最常用的,它提供了一种简单的方法,重复特定次数的动作。
当然还可以做一些定制工作,比如在遍历的过程中跳过一些元素。例如每隔一个元素对字符串进行遍历:
代码片段:
S = 'abcdefghijklmn'
for i in range(0,len(S),2):
print(S[i], end=',')
运行结果:
a,c,e,g,i,k,m,
当然,这只是一个示例,我们之前提到过的分片表达式才是实现该功能的最简单的方法:
代码片段:
S = 'abcdefghijklmn'
for c in S[::2]:
print(c, end=',')
运行结果:
a,c,e,g,i,k,m,
和文件迭代一样,这里range函数的优点也是明显的,它没有复制字符串,不会在python中再创建一个字符串列表,这对于很大的字符串来说,会节约不少空间。
2.2.zip的使用方法
**简单来说,zip可以用来并行迭代多个序列。**内置zip函数允许我们使用for循环来并行迭代多个序列。zip使用多个序列作为参数,然后返回元组的列表,将这些序列中的并排元素一一配对。
代码片段:
L1 = [1,2,3,4,5]
L2 = ['A','B','C','D','E']
for t in zip(L1,L2):
print(t, end=',')
运行结果:
(1, 'A'),(2, 'B'),(3, 'C'),(4, 'D'),(5, 'E'),
和range一样,zip在遍历时也是依次按需产生结果,而不是一次性显示所有结果
代码片段:
L1 = [1,2,3,4,5]
L2 = ['A','B','C','D','E']
print(zip(L1,L2))
运行结果:
<zip object at 0x000000000260ED08>
同样的,如果想一次性显示所有结果,则必须将其包含在一个list调用中,以便一次性显示所有结果
代码片段:
L1 = [1,2,3,4,5]
L2 = ['A','B','C','D','E']
print(list(zip(L1,L2)))
运行结果:
[(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')]
最后只说明一点,当zip的多个参数长度不同时,zip会以最短序列的长度为准来截断所得到的元组
代码片段:
L1 = [1,2,3,4,5]
L2 = ['A','B','C']
print(list(zip(L1,L2)))
运行结果:
[(1, 'A'), (2, 'B'), (3, 'C')]
回顾一下,之前我们谈到过,当字典的键和值必须在运行时计算产生时,zip函数可以用于产生这样的字典:
代码片段:
keys = ['A', 'B', 'C']
vals = [1, 2, 3]
D = dict(zip(keys,vals))
print(D)
运行结果:
{'C': 3, 'A': 1, 'B': 2}
2.3.enumerate的使用方法
**enumerate,简言之,就是用来同时产生偏移和元素。**有时我们在遍历的时候,既需要偏移值,又需要对应元素,那么内置函数enumerate就可以实现这个功能。
他在for循环的条件下每轮迭代返回一个包含偏移值和偏移元素的元组:(index,value)
代码片段:
S = 'spam'
for t in enumerate(S):
print(t,end=' ')
运行结果:
(0, 's') (1, 'p') (2, 'a') (3, 'm')
同样,他也是按需产生,而非一次性产生所有元素的列表
代码片段:
S = 'spam'
print(enumerate(S))
运行结果:
<enumerate object at 0x0000000001ED2558>
3.列表解析式与字典解析式
可能大家会问了,上面一直谈的是循环迭代方面的内容,这里的这些解析式是干什么用的?
3.1.列表解析式
列表解析式是python中的一个亮点语法。本质上就是用列表来构建列表,通过对已有列表中的每一项应用一个指定的表达式来构建出一个新的列表。列表解析式的优势是编码简单,运行起来很快。
列表解析式的三个核心要素是:
1.作用于输入序列的运算表达式;
2.对输入序列的循环表达式;
3.对输入序列的过滤条件,其中过滤条件是可选的。
我们也别光说一二三,来举个例子说说:
比如我们想要用列表a生成列表b,其中列表b中的每个元素都是a中对应元素的二次方
代码片段:
a = [1,2,3,4,5,6,7,8,9,10]
b = [x**2 for x in a]
print(b)
运行结果:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
这个例子中,输入序列是a,运算表达式是x2,循环表达式是for x in a**。这个例子没有使用过滤条件,因此就使用了列表a中的所有元素来构造列表b.
如果我们只想用列表a中所有能被3整除的元素来构造列表b呢,那就得用上过滤条件了。
代码片段:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [x**2 for x in a if x % 3 == 0]
print(b)
运行结果:
[9, 36, 81]
3.2.字典解析式
**同样,对于字典也有同样的用法:字典解析式。**他可以用字典以及列表等这些可以迭代的数据类型,来构造一个新的字典。
先看用字典构造字典
代码片段:
D1 = {'a': 1, 'b': 2, 'c': 3}
D2 = {k: v*2 for (k, v) in D1.items()}
print(D2)
运行结果:
{'b': 4, 'a': 2, 'c': 6}
再举一个用列表构造字典的例子:
代码片段:
D = {c:c*4 for c in ['a', 'b', 'c', 'd']}
print(D)
运行结果:
{'d': 'dddd', 'a': 'aaaa', 'c': 'cccc', 'b': 'bbbb'}
Python容器遍历的语法看上去简洁而清爽。解析式呢,我感觉是遍历语法的一种更高级的展现和应用,使用简洁,而且可读性也比较强,是非常常用的一种语法技巧。