Python序列操作之進(jìn)階篇
簡(jiǎn)介
Python 的序列(sequence)通常指一個(gè)可迭代的容器,容器中可以存放任意類(lèi)型的元素。列表和元組這兩種數(shù)據(jù)類(lèi)型是最常被用到的序列,python內(nèi)建序列有六種,除了剛剛有說(shuō)過(guò)的兩種類(lèi)型之外,還有字符串、Unicode字符串、buffer對(duì)像和最后一種xrange對(duì)像,這幾種都是不常使用的。本文講解了列表推導(dǎo)式、切片命名、列表元素排序、列表元素分組的使用方法。學(xué)習(xí)了 Python 基本的列表操作后,學(xué)習(xí)這些進(jìn)階的操作,讓我們寫(xiě)出的代碼更加優(yōu)雅簡(jiǎn)潔和 pythonic 。
列表推導(dǎo)式
當(dāng)我們想要根據(jù)某些規(guī)則來(lái)構(gòu)造一個(gè)列表時(shí),首先想到的應(yīng)該是列表推導(dǎo)式。列表推導(dǎo)式簡(jiǎn)化了循環(huán)操作,例如我們想要從一個(gè)原始文件名列表中獲取全部 .py 文件,在沒(méi)有列表推導(dǎo)式的情況下,我們通常會(huì)這樣做:
file_list = ['foo.py', 'bar.txt', 'spam.py', 'animal.png', 'test.py'] py_list = [] for file in file_list: if file.endswith('.py'): py_list.append(file) print(py_list) # output ['foo.py', 'spam.py', 'test.py']
而如果使用列表推導(dǎo)式則可簡(jiǎn)化為:
py_list = [f for f in file_list if f.endswith('.py')] print(py_list) # output ['foo.py', 'spam.py', 'test.py']
列表推導(dǎo)式的介紹網(wǎng)上資源很多,不再贅述。這里只強(qiáng)調(diào),當(dāng)你需要根據(jù)某個(gè)規(guī)則來(lái)構(gòu)造一個(gè)列表時(shí),首先應(yīng)該想一想,能否使用簡(jiǎn)潔的列表推導(dǎo)式來(lái)實(shí)現(xiàn)該需求,否則再回到常規(guī)的方式。
為切片命名
Python 的列表切片使用起來(lái)非常方便,但有時(shí)也會(huì)影響代碼可讀性。例如有一個(gè)字符串:
record = '..........19.6..........100..........'
19.6 為產(chǎn)品價(jià)格,100 為產(chǎn)品數(shù)量,那么計(jì)算總價(jià)格為:
但是如果這樣寫(xiě),可能過(guò)一段時(shí)間我們?cè)賮?lái)讀代碼時(shí)已經(jīng)忘記了 record[10:14]
、record[24:27]
切出來(lái)的究竟是什么?為了解決上述問(wèn)題,可以給切片命個(gè)名來(lái)增強(qiáng)可讀性。
record = '..........19.6..........100..........' price = slice(10, 14) count = slice(24, 27) total_price = float(record[price])*int(record[count])
slice 接收的參數(shù)格式為 slice(stop)
、slice(start, stop[, step])
。如果只接收了一個(gè)參數(shù),則等價(jià)于切片語(yǔ)法 [:stop]
,如果接收兩個(gè)參數(shù),則等價(jià)于切片語(yǔ)法 [start:stop]
,如果接收三個(gè)參數(shù),則等價(jià)于切片語(yǔ)法 [start:stop:step]
。
排序
排序相關(guān)的任務(wù)通常由內(nèi)置函數(shù) sorted 完成。需要排序的元素一般存放在一個(gè)列表容器中,列表可以存放任意類(lèi)型的元素,而 sorted 函數(shù)的 key 關(guān)鍵字使得我們能夠輕松地指定元素排序的關(guān)鍵字,讓排序變得異常簡(jiǎn)單。下面將給出幾個(gè)常見(jiàn)的排序例子以說(shuō)明 key 關(guān)鍵字的使用方法。注意 Python3 和 Python2 的排序方法不能通用,下面的例子只適用于 Python3 ,Python2 的排序方法未包含在本文中。
情況一
列表中的元素已經(jīng)是可比較元素,直接將列表傳入 sorted 函數(shù)即可返回一個(gè)已排序列表。默認(rèn)為升序排列,降序排列可以指定 reverse 參數(shù),例如:
>>> l = [3,5,4,1,8] >>> sorted(l) [1, 3, 4, 5, 8] >>> sorted(l, reverse=True) [8, 5, 4, 3, 1] >>>
情況二
需要排序的元素是一個(gè)元組或者字典,希望根據(jù)我指定的關(guān)鍵字來(lái)排序,例如有如下兩個(gè)列表:
l_v1 = [('b',2),('a',1),('c',3),('d',4)] l_v2 = [ {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} ]
l_v1 是一個(gè)元組列表, l_v2 是一個(gè)字典列表。對(duì) l_v1 我們希望根據(jù)元組中第二個(gè)元素來(lái)排序,對(duì) l_v2 我們希望根據(jù)字典的關(guān)鍵字 uid 進(jìn)行排序。
sorted 函數(shù)接收一個(gè)關(guān)鍵字參數(shù) key ,該參數(shù)指定一個(gè)可調(diào)用函數(shù),函數(shù)返回一個(gè)值(只要是可比較的),那么 sorted 函數(shù)將根據(jù)返回的關(guān)鍵字對(duì)列表中的元素進(jìn)行排序。
例如對(duì)上面的例子:
>>> l_v1 = [('b',2),('a',1),('c',3),('d',4)] >>> sorted(l_v1, key=lambda x: x[1]) [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> l_v2 = [ {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} ] >>> sorted(l_v2, key=lambda x: x['uid']) [{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}]
這里 lambda 函數(shù)是一個(gè)常用的技巧。lambda 關(guān)鍵字后邊的 x 是該函數(shù)接收的參數(shù),冒號(hào)后邊的表達(dá)式是該函數(shù)的返回值。對(duì) l_v1 來(lái)說(shuō),傳遞給參數(shù) x 的就是每一個(gè)元組,其返回元組的第二個(gè)元素用于排序;對(duì) l_v2 來(lái)說(shuō),傳遞給參數(shù) x 的就是列表中的每一個(gè)字典元素,其返回字典中 uid 對(duì)應(yīng)的值用于排序。
除了使用匿名函數(shù) lambda 這種通用的方法外,Python 標(biāo)準(zhǔn)庫(kù) operator 為我們提供了一個(gè) itemgetter 函數(shù)替代我們寫(xiě)的 lambda 函數(shù),且其性能會(huì)比使用 lambda 函數(shù)略有提升。
>>> from operator import itemgetter >>> l_v1 = [('b',2),('a',1),('c',3),('d',4)] >>> sorted(l_v1, key=itemgetter(1)) [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> l_v2 = [ {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} ] >>> sorted(l_v2, key=itemgetter('uid')) [ {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'} ]
以上例子均是返回一個(gè)單一的值用于排序關(guān)鍵字,前面說(shuō)過(guò),關(guān)鍵字 key 接收的函數(shù)可以返回任意的可比較對(duì)象。例如在 python 中,元組是可以比較的。對(duì)元組的比較規(guī)則為首先比較元組中第一個(gè)位置上的元素,如果相等,在比較第二個(gè)位置上的元素,依次類(lèi)推?;氐?l_v2 的例子,假設(shè)現(xiàn)在需求變了,我們首先對(duì) lname 對(duì)應(yīng)的值排序,如果 lname 對(duì)應(yīng)的值相等,那么再根據(jù) fname 確定其順序。
>>> l_v2 = [ {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} ] >>> sorted(l_v2, key=lambda x: (x['lname'], x['fname'])) [ {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'} ]
這個(gè)例子中,lambda 函數(shù)返回的不再是一個(gè)標(biāo)量值,而是一個(gè)元組 (x['lname'], x['fname'])
,根據(jù)元組的比較規(guī)則,首先根據(jù)元組的第一個(gè)位置上的元素 x['lname']
的大小排序,由于列表中有兩個(gè)字典其 lname 對(duì)應(yīng)的值都為 Jones,因此再根據(jù)元組第二個(gè)位置的元素 x['fname']
的值排序,由于 Big 比 Brian 要?。ò醋帜疙樞蛞来伪容^),所以 Big 排在了前面。
同樣使用 itemgetter 函數(shù)也是可以的,且性能會(huì)略有提升。此外我覺(jué)得 itemgetter 比 lambda 更加簡(jiǎn)潔和可讀一點(diǎn)。
>>> l_v2 = [ {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} ] >>> sorted(l_v2, key=itemgetter('lname', 'fname')) [ {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'} ]
情況三
需要排序的元素是一個(gè) Python 對(duì)象,我們希望根據(jù)其某個(gè)屬性值來(lái)排序。例如一個(gè)存放 User 對(duì)象的列表如下,根據(jù)其 name 屬性排序:
class User: def __init__(self, name): self.name = name def __str__(self): return 'User: %s' % self.name __repr__ = __str__ # 為了能夠讓 User 在解釋器中顯示為 'User: name' 的格式 user_list = [User('John'), User('David'), User('Big'), User('Alen')]
方法與前面的一樣,定義一個(gè)函數(shù)返回 User 的 name 屬性的值,把該函數(shù)傳給 sorted 的 key 參數(shù)。
>>> user_list = [User('John'), User('David'), User('Big'), User('Alen')] >>> sorted(user_list, key=lambda x: x.name) >>> sorted(user_list, key=lambda x: x.name) [User: Alen, User: Big, User: David, User: John]
但是,itemgetter 方法不再起作用,取而代之的是 attrgetter 方法。
>>> sorted(user_list, key=attrgetter('name')) [User: Alen, User: Big, User: David, User: John]
attrgetter 與 itemgetter 用法完全一致,只是 itemgetter 用于獲取某個(gè)位置索引或者字典關(guān)鍵字的取值,而 attrgetter 用于獲取對(duì)象的屬性值。
PS:sorted 返回的是原始列表的一個(gè)已排序的副本,而原始列表的順序并沒(méi)有任何變化。如果你只想就地排序(即排序原始列表本身),則直接調(diào)用 list 的 sort 方法即可:list.sort()
。其用法與 sorted 函數(shù)一樣,只是該函數(shù)沒(méi)有返回值,調(diào)用后原始列表已變?yōu)橐粋€(gè)已排序列表。
對(duì)序列中的元素進(jìn)行分組
和排序類(lèi)似,現(xiàn)想根據(jù)列表中元素的某個(gè)關(guān)鍵字分組,使關(guān)鍵字相同的元素分到同一組,并可以對(duì)分好的組進(jìn)行進(jìn)一步處理。例如有如下的一個(gè)列表:
rows = [ {'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '5148 N CLARK', 'date': '07/04/2012'}, {'address': '5800 E 58TH', 'date': '07/02/2012'}, {'address': '2122 N CLARK', 'date': '07/03/2012'}, {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}, {'address': '1060 W ADDISON', 'date': '07/02/2012'}, {'address': '4801 N BROADWAY', 'date': '07/01/2012'}, {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}, ]
列表的元素為字典,現(xiàn)想根據(jù)字典的 date 分組,使日期( date )相同的元素分到一個(gè)組。Python 的 itertools 模塊中的 groupby 函數(shù)可以很好地解決該問(wèn)題。為了使用 groupby 函數(shù),首先需要對(duì)列表排序:
>>> from operator import itemgetter >>> sorted_rows = sorted(rows, key=itemgetter('date'))
groupby 也和 sorted 一樣有一個(gè) key 關(guān)鍵字參數(shù),其接收一個(gè)可調(diào)用函數(shù),該函數(shù)返回的值被用做分組的關(guān)鍵字,其用法和 sorted 的 key 關(guān)鍵字參數(shù)一樣 。
>>> for date, items in groupby(sorted_rows, key=itemgetter('date')): print(date) for i in items: print(' ', i) 07/01/2012 {'address': '5412 N CLARK', 'date': '07/01/2012'} {'address': '4801 N BROADWAY', 'date': '07/01/2012'} 07/02/2012 {'address': '5800 E 58TH', 'date': '07/02/2012'} {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'} {'address': '1060 W ADDISON', 'date': '07/02/2012'} 07/03/2012 {'address': '2122 N CLARK', 'date': '07/03/2012'} 07/04/2012 {'address': '5148 N CLARK', 'date': '07/04/2012'} {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}
可以看到 groupby 返回的值分別是用于分組的關(guān)鍵字對(duì)應(yīng)的值和該組的全部成員。groupby 實(shí)際返回一個(gè)生成器,通過(guò)迭代即可分別對(duì)各組進(jìn)行處理。值得注意的一點(diǎn)是,分組前對(duì)列表排序這一步必不可少,否則對(duì)于非緊鄰的元素即使其值相同也會(huì)被分在不同組。
總結(jié)
以上就是關(guān)于python序列進(jìn)階篇的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家學(xué)習(xí)或者使用python能有所幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Python猴子補(bǔ)丁Monkey Patch用法實(shí)例解析
這篇文章主要介紹了Python猴子補(bǔ)丁Monkey Patch用法實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03Python 讀寫(xiě) Matlab Mat 格式數(shù)據(jù)的操作
這篇文章主要介紹了Python 讀寫(xiě) Matlab Mat 格式數(shù)據(jù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05Python密碼學(xué)XOR算法編碼流程及乘法密碼教程
這篇文章主要為大家介紹了Python密碼學(xué)XOR流程及乘法密碼教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Python利用txt文件對(duì)Mysql進(jìn)行增刪改查移
這篇文章主要介紹了如何在Python中利用TXT文件對(duì)Mysql中的記錄進(jìn)行增刪改查移,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)2021-12-12用Pycharm實(shí)現(xiàn)鼠標(biāo)滾輪控制字體大小的方法
今天小編就為大家分享一篇用Pycharm實(shí)現(xiàn)鼠標(biāo)滾輪控制字體大小的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01用python結(jié)合jieba和wordcloud實(shí)現(xiàn)詞云效果
詞云,顧名思義就是很多個(gè)單詞,然后通過(guò)出現(xiàn)的頻率或者比重之類(lèi)的標(biāo)準(zhǔn)匯聚成一個(gè)云朵的樣子嘛,其實(shí)呢現(xiàn)在網(wǎng)上已經(jīng)有很多能自動(dòng)生成詞云的工具了,比如Wordle,Tagxedo等等,Python也能實(shí)現(xiàn)這樣的效果,我們通過(guò)jieba庫(kù)和wordcloud庫(kù)也能十分輕松的完成詞云的構(gòu)建2017-09-09簡(jiǎn)單了解Python下用于監(jiān)視文件系統(tǒng)的pyinotify包
這篇文章主要介紹了Python下用于監(jiān)視文件系統(tǒng)的pyinotify包,pyinotify基于inotify事件驅(qū)動(dòng)機(jī)制,需要的朋友可以參考下2015-11-11