鍍金池/ 教程/ Python/ 語句(4)
標準庫 (4)
如何成為 Python 高手
標準庫 (6)
標準庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網(wǎng)站 (5)
文件(1)
練習
列表(3)
從小工到專家
除法
錯誤和異常 (2)
函數(shù)(1)
用 tornado 做網(wǎng)站 (7)
為做網(wǎng)站而準備
函數(shù)練習
標準庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網(wǎng)站 (3)
字符串(1)
函數(shù)(2)
寫一個簡單的程序
將數(shù)據(jù)存入文件
語句(5)
SQLite 數(shù)據(jù)庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網(wǎng)站 (6)
用 tornado 做網(wǎng)站 (2)
自省
語句(4)
錯誤和異常 (1)
用 tornado 做網(wǎng)站 (4)
集合(2)
列表(1)
標準庫 (1)
生成器
mysql 數(shù)據(jù)庫 (1)
第三方庫
實戰(zhàn)
運算符
類(3)
字典(2)
語句(1)
數(shù)和四則運算
語句(2)
文件(2)
MySQL 數(shù)據(jù)庫 (2)
電子表格
迭代器
mongodb 數(shù)據(jù)庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網(wǎng)站 (1)
標準庫 (5)
函數(shù)(4)
類(5)
字符串(2)
關于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據(jù)
常用數(shù)學函數(shù)和運算優(yōu)先級
字符串(3)
為計算做準備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯誤和異常 (3)
分析 Hello
Python 安裝
標準庫 (2)
列表(2)
元組

語句(4)

for 循環(huán)在 Python 中應用廣泛,所以,要用更多的篇幅來介紹。

并行迭代

關于迭代,在《列表(2)》中曾經(jīng)提到過“可迭代的(iterable)”這個詞,并給予了適當解釋,這里再次提到“迭代”,說明它在 Python 中占有重要的位置。

迭代,在 Python 中表現(xiàn)就是用 for 循環(huán),從序列對象中獲得一定數(shù)量的元素。

在前面一節(jié)中,用 for 循環(huán)來獲得列表、字符串、元組,乃至于字典的鍵值對,都是迭代。

現(xiàn)實中迭代不都是那么簡單的,比如這個問題:

問題:有兩個列表,分別是:a = [1,2,3,4,5], b = [9,8,7,6,5],要計算這兩個列表中對應元素的和。

解析:

太簡單了,一看就知道結果了。

很好,這是你的方法,如果是 computer 姑娘來做,應該怎么做呢?

觀察發(fā)現(xiàn)兩個列表的長度一樣,都是 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 的表現(xiàn)還不錯。不過,這種方法雖然解決問題了,但 Python 總不會局限于一個解決之道。于是又有一個內(nèi)建函數(shù) zip(),可以讓同樣的問題有不一樣的解決途徑。

zip 是什么東西?在交互模式下用 help(zip),得到官方文檔是:

zip(...) zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

seq1, seq2 分別代表了序列類型的數(shù)據(jù)。通過實驗來理解上面的文檔:

>>> 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 是一個內(nèi)置函數(shù),它的參數(shù)必須是某種序列數(shù)據(jù)類型,如果是字典,那么鍵視為序列。然后將序列對應的元素依次組成元組,做為一個 list 的元素。

下面是比較特殊的情況,參數(shù)是一個序列數(shù)據(jù)的時候,生成的結果樣子:

>>> 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]

多么優(yōu)雅的解決!

比較這個問題的兩種解法,似乎第一種解法適用面較窄,比如,如果已知給定的兩個列表長度不同,第一種解法就出問題了。而第二種解法還可以繼續(xù)適用。的確如此,不過,第一種解法也不是不能修訂的。

>>> 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']

我還是用第一個思路做的,經(jīng)過這么修正一下,也還能用。要注意一個細節(jié),在“加”的時候,不能直接用 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 循環(huán),可以這樣做(當然,看官如果有方法,歡迎貼出來)。

>>> 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() 還能這樣用。是的,本質(zhì)上是這么回事情。如果將上面這一行分解開來,看官就明白其中的奧妙了。

>>> 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)                          #這是函數(shù) dict() 的功能,將上述列表轉化為 dictionary
{'Python': 'lang', 'qiwsir.github.io': 'site', 'qiwsir': 'name'}

至此,是不是明白 zip()和循環(huán)的關系了呢?有了它可以讓某些循環(huán)簡化。

enumerate

這是一個有意思的內(nèi)置函數(shù),本來我們可以通過 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 中提供了一個內(nèi)置函數(shù) enumerate,能夠實現(xiàn)類似的功能

>>> for (i,day) in enumerate(week):
...     print day+' is '+str(i)
... 
monday is 0
sunday is 1
friday is 2

官方文檔是這么說的:

Return an enumerate object. sequence must be a sequence, an iterator, or some other object which supports iteration. The next() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over sequence:

順便抄錄幾個例子,供看官欣賞,最好實驗一下。

>>> 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>    

出現(xiàn)這個結果,用 list 就能實現(xiàn)轉換,顯示內(nèi)容.意味著可迭代。

>>> list(enumerate(mylist))
[(0, 'qiwsir'), (1, 703), (2, 'python')]

再設計一個小問題,練習一下這個函數(shù)。

問題:將字符串中的某些字符替換為其它的字符串。原始字符串"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"
... 

沒有什么異常現(xiàn)象,查看一下那個 raw_lst 列表,看看是不是把"Canglaoshi"替換為"PHP"了。

>>> raw_lst
['Do', 'you', 'love', 'Canglaoshi?', 'PHP', 'is', 'a', 'good', 'teacher.']

只替換了一個,還有一個沒有替換。為什么?仔細觀察發(fā)現(xiàn),沒有替換的那個是'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 的每個整數(shù)的平方,并且將結果放在 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,追求簡潔優(yōu)雅的 Python!

其官方文檔中有這樣一段描述,道出了 list 解析的真諦:

List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.

這就是 Python 有意思的地方,也是計算機高級語言編程有意思的地方,你只要動腦筋,總能找到驚喜的東西。

其實,不僅僅對數(shù)字組成的 list,所有的都可以如此操作。請在平復了激動的心之后,默默地看下面的代碼,感悟一下 list 解析的魅力。

>>> mybag = [' glass',' apple','green leaf ']   #有的前面有空格,有的后面有空格
>>> [one.strip() for one in mybag]              #去掉元素前后的空格
['glass', 'apple', 'green leaf']

上面的問題,都能用 list 解析來重寫。讀者不妨試試。

在很多情況下,list 解析的執(zhí)行效率高,代碼簡潔明了。是實際寫程序中經(jīng)常被用到的。


總目錄   |   上節(jié):語句(3)   |   下節(jié):語句(5)

如果你認為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。

上一篇:標準庫 (3)下一篇:語句(2)