Python語(yǔ)言中計(jì)數(shù)方法的演變過(guò)程是怎么樣的,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

創(chuàng)新互聯(lián)建站主營(yíng)西塞山網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都App定制開(kāi)發(fā),西塞山h5微信小程序搭建,西塞山網(wǎng)站營(yíng)銷推廣歡迎西塞山等地區(qū)企業(yè)咨詢
有時(shí)候,利用Python語(yǔ)言簡(jiǎn)潔、優(yōu)雅地解決問(wèn)題的方法,會(huì)隨著時(shí)間變化。隨著Python不斷進(jìn)化,統(tǒng)計(jì)列表元素?cái)?shù)量的方法也在改變。
以計(jì)算元素在列表中出現(xiàn)的次數(shù)為例,我們可以編寫出許多不同的實(shí)現(xiàn)方法。在分析這些方法時(shí),我們先不關(guān)注性能,只考慮代碼風(fēng)格。
要理解這些不同的實(shí)現(xiàn)方式,我們得先知道一些歷史背景。幸運(yùn)的是,我們生活在"future"世界,擁有一臺(tái)時(shí)間機(jī)器。接下來(lái),我們一起坐上時(shí)光機(jī),回到1997年吧。
if 語(yǔ)句
1997年1月1日,我們使用的是Python 1.4。現(xiàn)在有一個(gè)不同顏色組成的列表,我們想知道列表里每種顏色出現(xiàn)的次數(shù)。我們用字典來(lái)計(jì)算吧!
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = {} for c in colors: if color_counts.has_key(c): color_counts[c] = color_counts[c] + 1 else: color_counts[c] = 1
注意:我們沒(méi)有使用+=,因?yàn)樵隽抠x值直到Python 2.0才出現(xiàn);另外,我們也沒(méi)有使用c in color_counts這個(gè)慣用法(idiom),因?yàn)檫@也是Python 2.2中才發(fā)明的,
運(yùn)行上述代碼之后,我們會(huì)發(fā)現(xiàn)color_counts字典里,現(xiàn)在包含了列表中每種顏色的出現(xiàn)次數(shù)。
>>> color_counts
{'brown': 3, 'yellow': 2, 'green': 1, 'black': 1, 'red': 1}
上面的實(shí)現(xiàn)很簡(jiǎn)單。我們遍歷了每一種顏色,并判斷該顏色是否在字典中。如果不在,就在字典加入該顏色;如果在,就增加這種顏色的計(jì)數(shù)。
我們還可以把上面的代碼改寫為:
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = {} for c in colors: if not color_counts.has_key(c): color_counts[c] = 0 color_counts[c] = color_counts[c] + 1
如果列表稀疏度高(即列表中不重復(fù)的顏色數(shù)量很多),這段代碼可能運(yùn)行的會(huì)有點(diǎn)慢。因?yàn)槲覀儸F(xiàn)在要執(zhí)行兩個(gè)語(yǔ)句,而不是一個(gè)。但是我們不關(guān)心性能問(wèn)題,我們只關(guān)注編碼風(fēng)格。經(jīng)過(guò)思考,我們決定采用新版的代碼。
try代碼塊(Code Block)
1997年1月2日,我們使用的還是Python 1.4。今早醒來(lái)的時(shí)候,我們突然意識(shí)到:我們的代碼遵循的是“三思而后行”(Look Before You Leap,即事先檢查每一種可能出現(xiàn)的情況)原則,但實(shí)際上我們應(yīng)該按照“獲得諒解比獲得許可容易”(Easier to Ask Forgiveness, Than Permission,即不檢查,出了問(wèn)題由異常處理來(lái)處理)的原則進(jìn)行編程,因?yàn)楹笳吒雍?jiǎn)潔、優(yōu)雅。我們用try-except代碼塊來(lái)重構(gòu)下代碼吧:
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = {} for c in colors: try: color_counts[c] = color_counts[c] + 1 except KeyError: color_counts[c] = 1
現(xiàn)在,我們的代碼嘗試增加每種顏色的計(jì)數(shù)。如果某顏色不在字典里,那么就會(huì)拋出KeyError,我們隨之將該顏色的計(jì)數(shù)設(shè)置為1。
get方法
1998年1月1日,我們已經(jīng)升級(jí)到了Python 1.5。我們決定重構(gòu)之前的代碼,使用字典中新增的get方法。
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = {} for c in colors: color_counts[c] = color_counts.get(c, 0) + 1
現(xiàn)在,我們的代碼會(huì)遍歷每種顏色,從字典中獲取該顏色的當(dāng)前計(jì)數(shù)值。如果沒(méi)有這個(gè)計(jì)數(shù)值,則該顏色的計(jì)數(shù)值默認(rèn)為0,然后在數(shù)值的基礎(chǔ)上加1。***將字典中相應(yīng)鍵的值設(shè)置為新的計(jì)數(shù)。
把主要代碼都寫在一行里,感覺(jué)很酷,但是我們不敢完全肯定這種做法更加簡(jiǎn)潔、優(yōu)雅。我們覺(jué)得可能有點(diǎn)太聰敏了,所以還是撤銷了這次的重構(gòu)。
setdefault方法
2001年1月1日,我們現(xiàn)在使用的是Python 2.0。我們聽(tīng)說(shuō)字典類型現(xiàn)在有一個(gè)setdefault方法,決定利用它重構(gòu)我們的代碼。我們還決定使用新增加的+=增量賦值運(yùn)算符。
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = {} for c in colors: color_counts.setdefault(c, 0) color_counts[c] += 1
無(wú)論是否需要,我們?cè)诿恳淮窝h(huán)時(shí)都會(huì)調(diào)用setdefault方法。但這樣做,的確會(huì)讓代碼看上去可讀性更高。我們發(fā)現(xiàn)這種方法比之前的代碼更加簡(jiǎn)潔、優(yōu)雅,所以提交了此次修改。
fromkeys方法
2004年1月1日,我們使用的是Python 2.3。我們聽(tīng)說(shuō)字典新增了一個(gè)叫fromkeys的類方法(class method),可以利用列表中的元素作為鍵來(lái)構(gòu)建字典。我們使用新方法重構(gòu)了代碼:
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = dict.fromkeys(colors, 0) for c in colors: color_counts[c] += 1
這段代碼將不同的顏色作為鍵,創(chuàng)建了一個(gè)新的字典,每個(gè)鍵的值被默認(rèn)設(shè)置為0。這樣,我們?cè)黾用總€(gè)鍵的值時(shí),就不用擔(dān)心是否已經(jīng)進(jìn)行了設(shè)置。我們也不需要在代碼中進(jìn)行檢查或異常處理了,這看上去是個(gè)改進(jìn)。我們決定就這樣修改代碼。
推導(dǎo)式(Comprehension)與集合
2005年1月1日,我們現(xiàn)在用的是Python 2.4。我們發(fā)現(xiàn)可以利用集合(Python 2.3中發(fā)布,2.4版成為內(nèi)置類型)與列表推導(dǎo)式(Python 2.0中發(fā)布)來(lái)解決計(jì)數(shù)問(wèn)題。進(jìn)一步思考之后,我想起來(lái)Python 2.4中還發(fā)布了生成器表達(dá)式(generator expressions),我們***決定不用列表推導(dǎo)式,而是采用生成器表達(dá)式。
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = dict((c, colors.count(c)) for c in set(colors))
注意:我們這里使用的不是字典推導(dǎo)式,因?yàn)樽值渫茖?dǎo)式直到Python 2.7才被發(fā)明。
運(yùn)行成功了,而且只有一行代碼。但是這種代碼夠簡(jiǎn)潔、優(yōu)雅嗎 ?
我們想起了Python之禪(Zen of Python),這個(gè)Python編程指導(dǎo)原則起源于一個(gè)Python郵件列表,并悄悄地收進(jìn)了Python 2.2.1版本中。我們?cè)赗EPL(read-eval-print loop,交互式解釋器)界面中輸入import this:
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly. # 優(yōu)美勝過(guò)丑陋
Explicit is better than implicit. # 明確勝過(guò)含蓄
Simple is better than complex. # 簡(jiǎn)單勝過(guò)復(fù)雜
Complex is better than complicated. # 復(fù)雜勝過(guò)難懂
Flat is better than nested. # 扁平勝過(guò)嵌套
Sparse is better than dense. # 稀疏勝過(guò)密集
Readability counts. # 易讀亦有價(jià)
Special cases aren't special enough to break the rules. # 特例也不能特殊到打破規(guī)則
Although practicality beats purity. # 盡管實(shí)用會(huì)擊敗純潔
Errors should never pass silently. # 錯(cuò)誤永遠(yuǎn)不應(yīng)默默地溜掉
Unless explicitly silenced. # 除非明確地使其沉默
In the face of ambiguity, refuse the temptation to guess. # 面對(duì)著不確定,要拒絕猜測(cè)的誘惑
There should be one-- and preferably only one --obvious way to do it. # 應(yīng)該有一個(gè)–寧肯只有一個(gè)–明顯的實(shí)現(xiàn)方法
Although that way may not be obvious at first unless you're Dutch. # 也許這個(gè)方法開(kāi)始不是很明顯,除非你是荷蘭人
Now is better than never. #現(xiàn)在做也要?jiǎng)龠^(guò)不去做
Although never is often better than right now. # 盡管不做通常好過(guò)立刻做
If the implementation is hard to explain, it's a bad idea. # 如果實(shí)現(xiàn)很難解釋,那它就是一個(gè)壞想法
If the implementation is easy to explain, it may be a good idea. # 如果實(shí)現(xiàn)容易解釋,那它可能就是一個(gè)好想法
Namespaces are one honking great idea -- let's do more of those! # 命名空間是一個(gè)響亮的出色想法就讓我們多用用它們
我們的代碼變得更復(fù)雜,時(shí)間復(fù)雜度從O(n)增加到了O(n2);還變的更丑,可讀性更差了。我們那樣改,是一次有趣的嘗試,但是一行代碼的實(shí)現(xiàn)形式,沒(méi)有我們之前的方法簡(jiǎn)潔、優(yōu)雅。我們***還是決定撤銷修改。
defaultdict方法
2007年1月1日,我們使用的是Python 2.5。我們剛發(fā)現(xiàn),defaultdict已經(jīng)被加入標(biāo)準(zhǔn)庫(kù)。這樣,我們就可以把字典的默認(rèn)鍵值設(shè)置為0了。讓我們使用defaultdict重構(gòu)代碼:
from collections import defaultdict
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = defaultdict(int) for c in colors: color_counts[c] += 1
那個(gè)for循環(huán)現(xiàn)在變得真簡(jiǎn)單!這樣肯定是更加簡(jiǎn)潔、優(yōu)雅了。
我們發(fā)現(xiàn),color_counts這個(gè)變量的行為現(xiàn)在有點(diǎn)不同,但是它的確繼承了字典的特性,支持所有相同的映射功能。
>>> color_counts
defaultdict(<type 'int'>, {'brown': 3, 'yellow': 2, 'green': 1, 'black': 1, 'red': 1})
我們?cè)谶@里沒(méi)有把color_counts轉(zhuǎn)換成字典,而是假設(shè)其他的代碼也使用鴨子類型(duck typing, Python中動(dòng)態(tài)類型的一種,這里的意思是:其他代碼會(huì)將color_counts視作字典類型),不再改動(dòng)這個(gè)類似字典的對(duì)象。
Counter類
2011年1月1日,我們使用的是Python 2.7。別人告訴我們,之前使用defaultdict編寫的代碼,不再是統(tǒng)計(jì)顏色出現(xiàn)次數(shù)最簡(jiǎn)潔、優(yōu)雅的方法了。Python 2.7中新引入了一個(gè)Counter類,可以完全解決我們的問(wèn)題。
from collections import Counter
colors = ["brown", "red", "green", "yellow", "yellow", "brown", "brown", "black"] color_counts = Counter(colors)
還有比這更簡(jiǎn)單的方法嗎?這個(gè)一定是最簡(jiǎn)潔、優(yōu)雅的實(shí)現(xiàn)了。
與defaultdict一樣,Counter類返回的也是一個(gè)類似字典的對(duì)象(實(shí)際是字典的一個(gè)子類)。這對(duì)滿足我們的需求來(lái)說(shuō)足夠了,所以我們就這么干了。
>>> color_counts
Counter({'brown': 3, 'yellow': 2, 'green': 1, 'black': 1, 'red': 1})
性能考慮
請(qǐng)注意,在編寫這些實(shí)現(xiàn)方式時(shí),我們都沒(méi)有關(guān)注效率問(wèn)題。大部分方法的時(shí)間復(fù)雜度相同(O(n)),但是不同的Python語(yǔ)言實(shí)現(xiàn)形式(如CPython, PyPy,或者Jython)下,運(yùn)行時(shí)間會(huì)有差異。
盡管性能不是我們的主要關(guān)注點(diǎn),我還是在CPython 3.5.0的實(shí)現(xiàn)下測(cè)試了運(yùn)行時(shí)間。從中,你會(huì)發(fā)現(xiàn)一個(gè)有趣的現(xiàn)象:隨著列表中顏色元素的密度(即相同元素的數(shù)量)變化,每一種實(shí)現(xiàn)方法的相對(duì)效率也會(huì)不同。
根據(jù)Python之禪,“ 應(yīng)該有一個(gè)——寧肯只有一個(gè)明顯的實(shí)現(xiàn)方法”。這句話所說(shuō)的狀態(tài)值得追求,但事實(shí)是,并不總是只有一種明顯的方法。這個(gè)“明顯”的方法會(huì)隨著時(shí)間、需求和專業(yè)水平,不斷地變化。
看完上述內(nèi)容,你們掌握Python語(yǔ)言中計(jì)數(shù)方法的演變過(guò)程是怎么樣的的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
分享標(biāo)題:Python語(yǔ)言中計(jì)數(shù)方法的演變過(guò)程是怎么樣的
文章網(wǎng)址:http://chinadenli.net/article18/ipsodp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、網(wǎng)頁(yè)設(shè)計(jì)公司、企業(yè)網(wǎng)站制作、搜索引擎優(yōu)化、靜態(tài)網(wǎng)站、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)