for循环在python中应用广泛,所以,要用更多的篇幅来介绍。
并行迭代
关于迭代,在《列表(2)》中曾经提到过“可迭代的(iterable)”这个词,并给予了适当解释,这里再次提到“迭代”,说明它在python中占有重要的位置。
迭代,在python中表现就是用for循环,从序列对象中获得一定数量的元素。
在前面一节中,用for循环来获得列表、字符串、元组,乃至于字典的键值对,都是迭代。
现实中迭代不都是那么简单的,比如这个问题:
问题:有两个列表,分别是:a = [1,2,3,4,5], b = [9,8,7,6,5],要计算这两个列表中对应元素的和。
解析:
太简单了,一看就知道结果了。
很好,这是你的方法,如果是computer姑娘来做,应该怎么做呢?
观察发现两个列表的长度一样,都是5。那么对应元素求和,就是相同的索引值对应的元素求和,即a[i]+b[i],(i=0,1,2,3,4),这样一个一个地就把相应元素和求出来了。当然,要用for来做这个事情了。
>>> a = [1,2,3,4,5]
>>> b = [9,8,7,6,5]
>>> c = []
>>> for i in range(len(a)):
... c.append(a[i]+b[i])
...
>>> c
[10, 10, 10, 10, 10]
看来for的表现还不错。不过,这种方法虽然解决问题了,但python总不会局限于一个解决之道。于是又有一个内建函数zip()
,可以让同样的问题有不一样的解决途径。
zip是什么东西?在交互模式下用help(zip),得到官方文档是:
seq1, seq2分别代表了序列类型的数据。通过实验来理解上面的文档:
>>> a = "qiwsir"
>>> b = "github"
>>> zip(a,b)
[('q', 'g'), ('i', 'i'), ('w', 't'), ('s', 'h'), ('i', 'u'), ('r', 'b')]
如果序列长度不同,那么就以”the length of the shortest argument sequence”为准。
>>> c = [1,2,3]
>>> d = [9,8,7,6]
>>> zip(c,d)
[(1, 9), (2, 8), (3, 7)]
>>> m = {"name","lang"}
>>> n = {"qiwsir","python"}
>>> zip(m,n)
[('lang', 'python'), ('name', 'qiwsir')]
m,n是字典吗?当然不是。下面的才是字典呢。
>>> s = {"name":"qiwsir"}
>>> t = {"lang":"python"}
>>> zip(s,t)
[('name', 'lang')]
zip是一个内置函数,它的参数必须是某种序列数据类型,如果是字典,那么键视为序列。然后将序列对应的元素依次组成元组,做为一个list的元素。
下面是比较特殊的情况,参数是一个序列数据的时候,生成的结果样子:
>>> a
'qiwsir'
>>> c
[1, 2, 3]
>>> zip(c)
[(1,), (2,), (3,)]
>>> zip(a)
[('q',), ('i',), ('w',), ('s',), ('i',), ('r',)]
很好的zip()
!那么就用它来解决前面那个两个列表中值对应相加吧。
>>> d = []
>>> for x,y in zip(a,b):
... d.append(x+y)
...
>>> d
[10, 10, 10, 10, 10]
多么优雅的解决!
比较这个问题的两种解法,似乎第一种解法适用面较窄,比如,如果已知给定的两个列表长度不同,第一种解法就出问题了。而第二种解法还可以继续适用。的确如此,不过,第一种解法也不是不能修订的。
>>> a = [1,2,3,4,5]
>>> b = ["python","www.itdiffer.com","qiwsir"]
如果已知是这样两个列表,要讲对应的元素“加起来”。
>>> length = len(a) if len(a)<len(b) else len(b)
>>> length
3
首先用这种方法获得两个列表中最短的那个列表的长度。看那句三元操作,这是非常pythonic的写法啦。写出这句,就可以冒充高手了。哈哈。
>>> for i in range(length):
... c.append(str(a[i]) + ":" + b[i])
...
>>> c
['1:python', '2:www.itdiffer.com', '3:qiwsir']
我还是用第一个思路做的,经过这么修正一下,也还能用。要注意一个细节,在“加”的时候,不能直接用a[i]
,因为它引用的对象是一个int类型,不能跟后面的str类型相加,必须转化一下。
当然,zip()
也是能解决这个问题的。
>>> d = []
>>> for x,y in zip(a,b):
... d.append(x + y)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
报错!看错误信息,我刚刚提醒的那个问题就冒出来了。所以,应该这么做:
>>> for x,y in zip(a,b):
... d.append(str(x) + ":" + y)
...
>>> d
['1:python', '2:www.itdiffer.com', '3:qiwsir']
这才得到了正确结果。
切记:computer是一个姑娘,她非常秀气,需要敲代码的小伙子们耐心地、细心地跟她相处。
以上两种写法那个更好呢?前者?后者?哈哈。我看差不多了。
>>> result
[(2, 11), (4, 13), (6, 15), (8, 17)]
>>> zip(*result)
[(2, 4, 6, 8), (11, 13, 15, 17)]
zip()
还能这么干,是不是有点意思?
下面延伸一个问题:
问题:有一个dictionary,myinfor = {“name”:”qiwsir”,”site”:”qiwsir.github.io”,”lang”:”python”},将这个字典变换成:infor = {“qiwsir”:”name”,”qiwsir.github.io”:”site”,”python”:”lang”}
解析:
解法有几个,如果用for循环,可以这样做(当然,看官如果有方法,欢迎贴出来)。
>>> infor = {}
>>> for k,v in myinfor.items():
... infor[v]=k
...
>>> infor
{'python': 'lang', 'qiwsir.github.io': 'site', 'qiwsir': 'name'}
下面用zip()来试试:
>>> dict(zip(myinfor.values(),myinfor.keys()))
{'python': 'lang', 'qiwsir.github.io': 'site', 'qiwsir': 'name'}
呜呼,这是什么情况?原来这个zip()还能这样用。是的,本质上是这么回事情。如果将上面这一行分解开来,看官就明白其中的奥妙了。
>>> myinfor.values() #得到两个list
['python', 'qiwsir', 'qiwsir.github.io']
>>> myinfor.keys()
['lang', 'name', 'site']
>>> temp = zip(myinfor.values(),myinfor.keys()) #压缩成一个list,每个元素是一个tuple
>>> temp
[('python', 'lang'), ('qiwsir', 'name'), ('qiwsir.github.io', 'site')]
>>> dict(temp) #这是函数dict()的功能,将上述列表转化为dictionary
{'python': 'lang', 'qiwsir.github.io': 'site', 'qiwsir': 'name'}
至此,是不是明白zip()和循环的关系了呢?有了它可以让某些循环简化。
enumerate
这是一个有意思的内置函数,本来我们可以通过for i in range(len(list))
的方式得到一个list的每个元素索引,然后在用list[i]的方式得到该元素。如果要同时得到元素索引和元素怎么办?就是这样了:
>>> for i in range(len(week)):
... print week[i]+' is '+str(i) #注意,i是int类型,如果和前面的用+连接,必须是str类型
...
monday is 0
sunday is 1
friday is 2
python中提供了一个内置函数enumerate,能够实现类似的功能
>>> for (i,day) in enumerate(week):
... print day+' is '+str(i)
...
monday is 0
sunday is 1
friday is 2
官方文档是这么说的:
顺便抄录几个例子,供看官欣赏,最好实验一下。
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
对于这样一个列表:
>>> mylist = ["qiwsir",703,"python"]
>>> enumerate(mylist)
<enumerate object at 0xb74a63c4>
出现这个结果,用list就能实现转换,显示内容.意味着可迭代。
>>> list(enumerate(mylist))
[(0, 'qiwsir'), (1, 703), (2, 'python')]
再设计一个小问题,练习一下这个函数。
问题:将字符串中的某些字符替换为其它的字符串。原始字符串”Do you love Canglaoshi? Canglaoshi is a good teacher.”,请将”Canglaoshi”替换为”PHP”.
解析:
>>> raw = "Do you love Canglaoshi? Canglaoshi is a good teacher."
这是所要求的那个字符串,当时,不能直接对这个字符串使用enumerate()
,因为它会变成这样:
>>> list(enumerate(raw))
[(0, 'D'), (1, 'o'), (2, ' '), (3, 'y'), (4, 'o'), (5, 'u'), (6, ' '), (7, 'l'), (8, 'o'), (9, 'v'), (10, 'e'), (11, ' '), (12, 'C'), (13, 'a'), (14, 'n'), (15, 'g'), (16, 'l'), (17, 'a'), (18, 'o'), (19, 's'), (20, 'h'), (21, 'i'), (22, '?'), (23, ' '), (24, 'C'), (25, 'a'), (26, 'n'), (27, 'g'), (28, 'l'), (29, 'a'), (30, 'o'), (31, 's'), (32, 'h'), (33, 'i'), (34, ' '), (35, 'i'), (36, 's'), (37, ' '), (38, 'a'), (39, ' '), (40, 'g'), (41, 'o'), (42, 'o'), (43, 'd'), (44, ' '), (45, 't'), (46, 'e'), (47, 'a'), (48, 'c'), (49, 'h'), (50, 'e'), (51, 'r'), (52, '.')]
这不是所需要的。所以,先把raw转化为列表:
>>> raw_lst = raw.split(" ")
然后用enumerate()
>>> for i, string in enumerate(raw_lst):
... if string == "Canglaoshi":
... raw_lst[i] = "PHP"
...
没有什么异常现象,查看一下那个raw_lst列表,看看是不是把”Canglaoshi”替换为”PHP”了。
>>> raw_lst
['Do', 'you', 'love', 'Canglaoshi?', 'PHP', 'is', 'a', 'good', 'teacher.']
只替换了一个,还有一个没有替换。为什么?仔细观察发现,没有替换的那个是’Canglaoshi?’,跟条件判断中的”Canglaoshi”不一样。
修改一下,把条件放宽:
>>> for i, string in enumerate(raw_lst):
... if "Canglaoshi" in string:
... raw_lst[i] = "PHP"
...
>>> raw_lst
['Do', 'you', 'love', 'PHP', 'PHP', 'is', 'a', 'good', 'teacher.']
好的。然后呢?再转化为字符串?留给读者试试。
list解析
先看下面的例子,这个例子是想得到1到9的每个整数的平方,并且将结果放在list中打印出来
>>> power2 = []
>>> for i in range(1,10):
... power2.append(i*i)
...
>>> power2
[1, 4, 9, 16, 25, 36, 49, 64, 81]
python有一个非常有意思的功能,就是list解析,就是这样的:
>>> squares = [x**2 for x in range(1,10)]
>>> squares
[1, 4, 9, 16, 25, 36, 49, 64, 81]
看到这个结果,看官还不惊叹吗?这就是python,追求简洁优雅的python!
其官方文档中有这样一段描述,道出了list解析的真谛:
这就是python有意思的地方,也是计算机高级语言编程有意思的地方,你只要动脑筋,总能找到惊喜的东西。
其实,不仅仅对数字组成的list,所有的都可以如此操作。请在平复了激动的心之后,默默地看下面的代码,感悟一下list解析的魅力。
>>> mybag = [' glass',' apple','green leaf '] #有的前面有空格,有的后面有空格
>>> [one.strip() for one in mybag] #去掉元素前后的空格
['glass', 'apple', 'green leaf']
上面的问题,都能用list解析来重写。读者不妨试试。
在很多情况下,list解析的执行效率高,代码简洁明了。是实际写程序中经常被用到的。
转载请注明:www.ainoob.cn » 零基础学Python:语句(4)