本文摘自朱雷老師所著《Python工匠》一書內(nèi)容,作為筆記予以記錄。
列表、元組、字典、集合是Python中4中內(nèi)置容器類型,是Python語言中最為重要的組成部分,在《Python工匠》第三章容器類型中做了重要知識(shí)點(diǎn)的介紹,并引申出了對(duì)象的可變性、可哈希性等諸多基礎(chǔ)概念,在其它的Python書籍中很少讀到見底如此之深,特別有用的知識(shí)內(nèi)容,特此記錄。
內(nèi)置容器功能豐富,基于它構(gòu)建的自定義容器更為強(qiáng)大,能夠幫助我們完成許多有趣的事情,在本文后面將摘錄作者自定義字典類型,優(yōu)化了一個(gè)日志分析腳本。
雖然無需了解類表的底層實(shí)現(xiàn)原理就可以使用列表,但如果能深入了解列表是基于數(shù)組實(shí)現(xiàn)的,就能避開一些性能陷阱,知道在什么情況下應(yīng)該選擇其它數(shù)據(jù)機(jī)構(gòu)實(shí)現(xiàn)某些需求。
一、《Python工匠》第三章容器類型中的知識(shí)總結(jié):
(1)基礎(chǔ)知識(shí)
- 在進(jìn)行函數(shù)調(diào)用時(shí),傳遞的不是變量的值或者引用,而是變量所指對(duì)象的引用
- Python內(nèi)置類型可以分為可變與不可變兩種,可變性會(huì)影響一些操作的行為,比如+=
- 對(duì)于可變類型,必要時(shí)對(duì)其進(jìn)行拷貝操作,能避免產(chǎn)生意料之外的影響
- 常見的淺拷貝方式:copy.copy、推導(dǎo)式、切片操作
- 使用copy.deepcopy可以進(jìn)行深拷貝操作
(2)列表與元組
- 使用enumerate可以在遍歷列表的同時(shí)獲取下標(biāo)
- 函數(shù)的多返回值其實(shí)是一個(gè)元組
- 不存在元組推導(dǎo)式(表達(dá)式),但可以使用tuple函數(shù)來將生成器表達(dá)式轉(zhuǎn)換為元組
- 元組經(jīng)常用來表示一些結(jié)構(gòu)化數(shù)據(jù)
(3)字典與集合
- 在Python3.7版本前,字典類型是無序的,之后變?yōu)楸A魯?shù)據(jù)的插入順序
- 使用OrderedDict可以在Python3.7以前的版本里獲得有序字典
- 只有可哈希的對(duì)象才能存入集合,或者作為字典的鍵使用
- 使用有序字典OrderedDict可以快速實(shí)現(xiàn)有序去重
- 使用fonzenset可以獲得一個(gè)不可變的集合對(duì)象
- 集合可以方便地進(jìn)行集合運(yùn)算,計(jì)算交集、并集等
- 不要通過繼承dict來創(chuàng)建自定義字典類型
(4)代碼可讀性技巧
- 具名元組比普通元組可讀性更強(qiáng)
- 列表推導(dǎo)式可以更快速地完成遍歷、過濾、處理以及構(gòu)建新列表操作
- 不要編寫過于復(fù)雜的推導(dǎo)式,用樸實(shí)的代碼替代就好
- 不要把推導(dǎo)式當(dāng)做代碼量更少的循環(huán),寫普通循環(huán)就好
(5)代碼可維護(hù)性技巧
- 當(dāng)訪問的字典鍵不存在時(shí),可以選擇捕獲異?;蛳茸雠袛啵瑑?yōu)先推薦捕獲異常
- 使用get、setdefault、帶參數(shù)的pop方法可以簡(jiǎn)化邊界處理邏輯
- 使用具名元組作為返回值,比普通元組更好擴(kuò)展
- 當(dāng)字典鍵不存在時(shí),使用defaultdict可以簡(jiǎn)化處理
- 繼承MutalbeMapping可以方便地創(chuàng)建自定義字典類,封裝處理邏輯
- 用生成器按需返回成員,比直接返回一個(gè)列表更靈活,也更省內(nèi)存
- 使用動(dòng)態(tài)解包語法可以方便地合并字典
- 不要在遍歷列表的同時(shí)修改,否則會(huì)出現(xiàn)不可預(yù)期的結(jié)果
(6)代碼性能要點(diǎn)
- 列表的底層實(shí)現(xiàn)決定了它的頭部操作很慢,deque類型則沒有這個(gè)問題
- 當(dāng)需要判斷某個(gè)成員在容器中是否存在時(shí),使用字典/集合更快
二、重要知識(shí)點(diǎn)與使用技巧
(1)基本概念
列表(list)是一種非常經(jīng)典的容器類型,通常用來存放多個(gè)同類對(duì)象,比如從1到10的所有整數(shù)。一般使用中括號(hào)[]或者list()內(nèi)置函數(shù)創(chuàng)建,還有列表推導(dǎo)式。
元組(tuple)和列表非常相似,但跟列表不同,它不能夠被修改。這意味著元組完成初始化后就沒法再改動(dòng)了(例外的是,元組中有列表元素,這個(gè)列表還是可以更改其中元素的)。一般使用圓括號(hào)()或者tuple()內(nèi)置函數(shù)創(chuàng)建,無法直接使用推導(dǎo)式生成元組。
字典(dict)類型存放的是一個(gè)個(gè)鍵值對(duì)(key:value)。一般使用大括號(hào){}或者dict()內(nèi)置函數(shù)創(chuàng)建,還有字典推導(dǎo)式創(chuàng)建。
集合(set)它的特點(diǎn)是成員不能重復(fù),所以經(jīng)常用來去重(剔除重復(fù)元素),使用大括號(hào)表示,但是不能直接使用{}來定義一個(gè)空集合,因?yàn)閧}表示一個(gè)空字典。需要使用set()函數(shù)來創(chuàng)建。
>>> numbers =[1,2,3,2,3,4,5]
>>> set(numbers)? ? # 實(shí)現(xiàn)去重
{1, 2, 3, 4, 5}? ?
>>>?
(2)理解列表的可變性
Python里的內(nèi)置數(shù)據(jù)類型,大致上可以分為可變與不可變兩種。
可變(mutable):列表、字典、集合
不可變(immutable):整數(shù)、浮點(diǎn)數(shù)、字符串、字節(jié)串、元組
在學(xué)習(xí)Python時(shí),理解類型的可變性是非常重要的一課。下面通過2段代碼來理解最常見的場(chǎng)景“函數(shù)調(diào)用”來演示。
示例一:為字符串追加內(nèi)容
在這個(gè)示例里,定義了一個(gè)往字符串追加內(nèi)容的函數(shù)add_str(),并在外層用一個(gè)字符串參數(shù)調(diào)用該函數(shù):
def add_str(in_func_obj):
'''給一個(gè)字符串追加內(nèi)容'''
print(f'add_str函數(shù)內(nèi)打印信息,追加內(nèi)容之前: 函數(shù)傳入變量in_func_obj = "{in_func_obj}"')
in_func_obj += ' suffix'
print(f'add_str函數(shù)內(nèi)打印信息,追加內(nèi)容之后: 函數(shù)傳入變量in_func_obj = "{in_func_obj}"')
# 原始字符串變量
orig_obj = 'foo'
# 打印出字符串變量orig_obj的初始化值
print(f'執(zhí)行add_str()函數(shù)前,打印信息,字符串變量初始化值 orig_obj = "{orig_obj}"')
# 調(diào)用add_str函數(shù),打印的信息
add_str(orig_obj)
# 打印出字符串變量orig_obj的值,執(zhí)行add_str()函數(shù)后
print(f'執(zhí)行add_str()函數(shù)后,打印信息,字符串變量初始化值 orig_obj = "{orig_obj}"')
運(yùn)行上面代碼會(huì)發(fā)現(xiàn),創(chuàng)建的orig_obj(字符串)對(duì)象,作為參數(shù)傳入函數(shù)add_str()后,值沒有變化。
示例二:為列表追加內(nèi)容
在下面的代碼中,保留一模一樣的代碼邏輯,但是把orig_obj換成了列表對(duì)象:
def add_list(in_func_obj):
'''給一個(gè)字符串追加內(nèi)容'''
print(f'add_str函數(shù)內(nèi)打印信息,追加內(nèi)容之前: 函數(shù)傳入變量in_func_obj = "{in_func_obj}"')
in_func_obj += ['baz']
print(f'add_str函數(shù)內(nèi)打印信息,追加內(nèi)容之后: 函數(shù)傳入變量in_func_obj = "{in_func_obj}"')
# 原始字符串變量
orig_obj = ['foo','bar']
# 打印出字符串變量orig_obj的初始化值
print(f'執(zhí)行add_list()函數(shù)前,打印信息,字符串變量初始化值 orig_obj = "{orig_obj}"')
# 調(diào)用add_str函數(shù),打印的信息
add_list(orig_obj)
# 打印出字符串變量orig_obj的值,執(zhí)行add_list()函數(shù)后
print(f'執(zhí)行add_list()函數(shù)后,打印信息,字符串變量初始化值 orig_obj = "{orig_obj}"')
執(zhí)行后會(huì)發(fā)現(xiàn)結(jié)果大不一樣,列表變量orig_obj傳入函數(shù)后,值發(fā)生了更改。
這是因?yàn)镻ython在進(jìn)行函數(shù)調(diào)用傳參時(shí),采用的既不是值傳參,也不是引用傳參,而是傳遞了“變量所指對(duì)象的引用”。
換個(gè)角度說,相當(dāng)于做了一次變量賦值,執(zhí)行:in_func_obj = orig_obj
所以,在函數(shù)內(nèi)部執(zhí)行in_func_obj += ...等操作時(shí),是否會(huì)影響外部變量,只取決與in_func_obj所指向的對(duì)象本身是否可變。
字符串對(duì)象在Python中是不可變的數(shù)據(jù)類型,經(jīng)過賦值,是生成了一個(gè)新對(duì)象(值)in_func_obj,包括對(duì)其進(jìn)行操作。
而列表是可變類型數(shù)據(jù)對(duì)象,經(jīng)過賦值新變量,但是新變量依然是指向原對(duì)象(相當(dāng)于起了一個(gè)別名),對(duì)其進(jìn)行+=操作,原對(duì)象orig_obj值也自然是變化的。
(3)函數(shù)返回多個(gè)結(jié)果,其實(shí)就是返回元組文章來源:http://www.zghlxwxcb.cn/news/detail-824177.html
在Python中,函數(shù)可以一次返回多個(gè)結(jié)果,其實(shí)是通過返回一個(gè)元組來實(shí)現(xiàn)的。文章來源地址http://www.zghlxwxcb.cn/news/detail-824177.html
def get_rectangle():
"""返回長方形的寬和高"""
width = 100
height = 60
return width,height
# 獲取函數(shù)的多個(gè)值
regult = get_rectangle()
print(regult) # 輸出(100,20),是一個(gè)元組類型
# 將函數(shù)返回值一次賦值給多個(gè)變量,其實(shí)就是對(duì)元組做了一次解包
width,height = get_rectangle()
print(width,height) # 輸出:100 60
到了這里,關(guān)于Python學(xué)習(xí)筆記--容器類型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!