Python神器函數(shù)sorted():3個(gè)您不得不看的特性
作為一種通用語(yǔ)言,Python已在各種學(xué)術(shù)和工業(yè)領(lǐng)域逐漸流行,用于科學(xué)計(jì)算,工程,Web開(kāi)發(fā)和許多其他用途。 Python的一項(xiàng)引人入勝的功能是它是如此靈活,以至于同一功能可以有多個(gè)實(shí)現(xiàn)。讓我們考慮以下簡(jiǎn)單的示例。
- >>> # sort a list using sort()
- >>> names0 = ['Danny', 'Johnny', 'Billy', 'Donny']
- >>> names0.sort()
- >>> names0['Billy', 'Danny', 'Donny', 'Johnny']
- >>>>>> # sort a list using sorted()
- >>> names1 = ['Danny', 'Johnny', 'Billy', 'Donny']
- >>> sorted(names1)['Billy', 'Danny', 'Donny', 'Johnny']>>>
[“比利”,“丹尼”,“唐尼”,“約翰尼”]
在上面的代碼中,我們創(chuàng)建了兩個(gè)列表:names0和names1,并使用sort()和sorted()函數(shù)分別對(duì)它們進(jìn)行排序。顯然,我們能夠以相同順序在列表中獲得。
盡管sort()和sorted()函數(shù)之間的相似之處,但我想指出,幾乎總是要使用sorted()而不是sort()。這是三個(gè)原因。
1. 與任何迭代器的兼容性
第一個(gè)原因是sorted()函數(shù)更靈活,因?yàn)樗梢耘c任何可迭代對(duì)象一起使用。相比之下,sort()函數(shù)僅適用于列表。如果您不知道什么是可迭代的,可以參考下面的我的上一篇文章。簡(jiǎn)而言之,可迭代對(duì)象是可以在迭代中進(jìn)行迭代的Python對(duì)象,例如元組,列表,集合和字典。
讓我們根據(jù)兼容的數(shù)據(jù)類型比較sorted()和sort()。需要注意的一件事是,這兩種功能的使用方式存在細(xì)微的差異。 sorted()函數(shù)將iterable作為參數(shù),而sort()函數(shù)的調(diào)用者則使用點(diǎn)表示法調(diào)用該函數(shù)。
- >>> # sort a tuple
- >>> _ = (3, 5, 4).sort()
- Traceback (most recent call last): File "<stdin>", line 1, in <module>
- AttributeError: 'tuple' object has no attribute 'sort'
- >>> _ = sorted((3, 5, 4))
- >>>>>> # sort a dictionary>>> _ = {2: 'two', 0: 'zero', 1: 'one'}.sort()
- Traceback (most recent call last): File "<stdin>", line 1, in <module>
- AttributeError: 'dict' object has no attribute 'sort'
- >>> _ = sorted({2: 'two', 0: 'zero', 1: 'one'})
- >>>>>> # sort a set
- >>> _ = set([2, 3, 4]).sort()
- Traceback (most recent call last): File "<stdin>", line 1, in <module>
- AttributeError: 'set' object has no attribute 'sort'
- >>> _ = sorted(set([2, 3, 4]))
如上面的代碼所示,元組,字典和集合均無(wú)法調(diào)用sort()函數(shù)。實(shí)際上,sort()函數(shù)是列表對(duì)象的實(shí)例方法,而不是其他集合對(duì)象的實(shí)例方法,這意味著此函數(shù)僅可用于列表對(duì)象。相比之下,元組,字典和集合都可以通過(guò)sorted()函數(shù)進(jìn)行排序,因?yàn)樗羞@些數(shù)據(jù)類型都是可迭代的,因此使其適合使用sorted()函數(shù)。
2. 創(chuàng)建列表的便利
第二個(gè)原因是sorted()函數(shù)將按所需順序?qū)傻鷮?duì)象進(jìn)行排序后將返回一個(gè)列表對(duì)象。因此,這是構(gòu)建新列表的便捷方法。但是,sort()函數(shù)會(huì)更改調(diào)用此方法的列表的順序,我們稱此順序?yàn)榫偷嘏判颉4送?,此函?shù)隱式返回None(有時(shí),我們可以說(shuō),當(dāng)隱式返回值為None時(shí),它不返回任何內(nèi)容)。
讓我們考慮以下假設(shè)示例。我們從一個(gè)名為sales_dict的字典開(kāi)始,該字典保存全年的銷售記錄。我們要根據(jù)銷售額創(chuàng)建一個(gè)按降序排列的記錄列表。
- >>> # records of sales in a dictionary
- >>> sales_dict = {'Spring': 1000, 'Summer': 950, 'Fall': 1030, 'Winter': 1200}
- >>>>>> # create a list object of sales records
- >>> sales_list0 = sorted(sales_dict.items(), key=lambda x: x[1], reverse=True)
- >>> sales_list0[('Winter', 1200), ('Fall', 1030), ('Spring', 1000), ('Summer', 950)]
- >>>>>> sales_list1 = list(sales_dict.items())>>> sales_list1.sort(key=lambda x: x[1], reverse=True)
- >>> sales_list1[('Winter', 1200), ('Fall', 1030), ('Spring', 1000), ('Summer', 950)]
在上面的代碼中,我們只需要使用sorted()函數(shù)編寫一行代碼即可獲得所需的結(jié)果。但是,使用sort()函數(shù),我們必須編寫兩行代碼。值得注意的是,由于某人可能會(huì)誤認(rèn)為,我們無(wú)法通過(guò)使用點(diǎn)符號(hào)來(lái)組合這兩行來(lái)生成所需的列表對(duì)象。
- >>> # combine the two lines
- >>> sales_list2 = list(sales_dict.items()).sort(key=lambda x: x[1], reverse=True)
- >>> sales_list2>>> type(sales_list2)
- <class 'NoneType'>
- >>> print(sales_list2)
- None
如上面的代碼所示,通過(guò)組合兩行,我們得到的是None值。這是因?yàn)閟ort()函數(shù)的返回值為None,而不是調(diào)用該函數(shù)的列表對(duì)象。
3. 與迭代集成
由于sorted()函數(shù)返回列表,而sort()函數(shù)返回None,這種區(qū)別的含義是什么?好吧,在許多情況下,我們期望有可迭代對(duì)象,但沒(méi)有NoneType對(duì)象。一種這樣的場(chǎng)景是迭代,畢竟這是我們經(jīng)常使用列表對(duì)象執(zhí)行的一項(xiàng)關(guān)鍵操作。
考慮以下示例。我們有兩個(gè)字典分別保存第一學(xué)期和第二學(xué)期的分?jǐn)?shù)。目的是創(chuàng)建一個(gè)報(bào)告卡,總結(jié)每個(gè)學(xué)生的表現(xiàn),并按姓名進(jìn)行排序。
- >>> # test results for the first semester
- >>> results1 = {'John': 95, 'Danny': 80, 'Zack': 98}
- >>>>>> # test results for the second semester
- >>> results2 = {'Danny': 84, 'Zack': 95, 'John': 88}
- >>>>>> # generate the report card>>> for name, score in sorted(results2.items()):
- ... print(f'{name} | Spring: {results1[name]} | Fall: {score}')
- ... Danny | Spring: 80 | Fall: 84
- John | Spring: 95 | Fall: 88
- Zack | Spring: 98 | Fall: 95
在上面的代碼中,我們注意到這兩個(gè)字典都沒(méi)有期望的輸出順序,因此,我們將使用sorted()函數(shù)對(duì)字典進(jìn)行排序。如您所見(jiàn),我們可以將排序后的結(jié)果直接集成到for循環(huán)中,因?yàn)閟orted()函數(shù)返回排序后的列表。
您可能已經(jīng)預(yù)料到,如果我們?cè)谶@種情況下嘗試使用sort()函數(shù),將會(huì)發(fā)生什么。請(qǐng)參閱下面的更多細(xì)節(jié)。
- >>> for name, score in list(results2.items()).sort():
- ... print(f'{name} | Spring: {results1[name]} | Fall: {score}')
- ... Traceback (most recent call last): File "<stdin>", line 1, in <module>
- TypeError: 'NoneType' object is not iterable
總結(jié)
在本文中,我們討論了為什么幾乎應(yīng)該始終使用sorted()函數(shù)而不是sort()函數(shù)的三個(gè)原因。
- sorted()函數(shù)更靈活,因?yàn)樗膳c任何可迭代對(duì)象一起使用,這與只適用于列表的sort()函數(shù)不同。
- sorted()函數(shù)是創(chuàng)建排序列表的便捷方法。
- sorted()函數(shù)可以方便地與迭代集成。
篇尾思考
最后但并非最不重要的一點(diǎn)是,您可能想知道何時(shí)應(yīng)該考慮使用sort()函數(shù)。 對(duì)于這個(gè)問(wèn)題,我沒(méi)有確切的答案,但是我可以想到的一種情況是,當(dāng)我們只處理列表對(duì)象而又不希望得到返回的列表時(shí)。 畢竟,sorted()函數(shù)將生成一個(gè)新列表,因此,當(dāng)列表特別大時(shí),使用sorted()函數(shù)創(chuàng)建新列表的內(nèi)存使用效率不高。
考慮簡(jiǎn)單的例子。 我們需要對(duì)每個(gè)嵌套列表進(jìn)行排序。 在某些情況下,列表可能非常大。 使用sort()函數(shù)只會(huì)對(duì)原始列表進(jìn)行排序,從而避免創(chuàng)建不必要的新列表對(duì)象。
- >>> # simplified nested lists; each list can be much larger
- >>> group_scores = [[7, 3, 5], [3, 2, 8], [9, 4, 5]]
- >>> for scores in group_scores:
- ... scores.sort()
- ... >>> group_scores[[3, 5, 7], [2, 3, 8], [4, 5, 9]]
原文:
https://medium.com/swlh/3-reasons-why-you-should-almost-always-use-sorted-in-python-9fe122e6ce71