Python中列表乘法和列表推導(dǎo)式的區(qū)別舉例詳解
可變對(duì)象與不可變對(duì)象
python中對(duì)象有兩種類型:
- 可變對(duì)象類型:list、dict、set
- 不可變對(duì)象類型:tuple、string、int、float、bool
我們可以簡(jiǎn)單理解為:
- 可變對(duì)象類型的變量中記錄是:對(duì)象的地址值
- 不可變對(duì)象類型的變量中記錄時(shí):對(duì)象的值
可變對(duì)象類型變量 list1 和 list2 可以通過(guò)相同地址值,指向同一個(gè)對(duì)象
list1 = [1, 2, 3, 4, 5] list2 = list1 # 將list1的地址值賦給list2,使得list1,list2指向同一個(gè)對(duì)象 list1[0] = 2 # list1 修改對(duì)象內(nèi)容 print(list1) print(list2) # list2 和 list1 指向的是同一個(gè)對(duì)象,因此list2打印結(jié)果和list1相同
但是不可變對(duì)象類型的變量,不具備上面特點(diǎn)
num1 = 10 num2 = num1 num1 -= 1 print(num1) # 9 print(num2) # 10
生成含 x 個(gè) 不可變對(duì)象 的列表
列表乘法
list1 = [0] * 2
列表推導(dǎo)式
list2 = [0 for _ in range(2)]
由于 0 是不可變對(duì)象,因此這兩種方式生成的列表沒(méi)有區(qū)別。
生成含 x 個(gè) 可變對(duì)象 的列表
列表乘法
list1 = [[]] * 2
列表推導(dǎo)式
list2 = [[] for _ in range(2)]
[]列表,屬于可變對(duì)象,此時(shí)上面兩種方式生成的列表是有區(qū)別的
list1 = [[]] * 2 list2 = [[] for _ in range(2)] print(list1) # [[], []] print(list2) # [[], []] list1[0].append(0) list2[0].append(0) print(list1) # [[0], [0]] print(list2) # [[0], []]
通過(guò)運(yùn)行上面代碼,我們可以發(fā)現(xiàn),list1的打印結(jié)果似乎不太對(duì)勁。我們只是向 list1[0] 中追加了一個(gè)數(shù)值0,但是list1[1] 也被追加了一個(gè)數(shù)值0。
而 list2 沒(méi)有發(fā)生這樣的問(wèn)題。
列表類型屬于可變對(duì)象類型,列表類型的變量本質(zhì)記錄的是對(duì)象的地址值,我們可以使用id函數(shù)來(lái)獲取對(duì)象的地址值,因此我們可以將 list1 和 list2 內(nèi)部元素的地址值打印出來(lái)看看
list1 = [[]] * 2 list2 = [[] for _ in range(2)] print(list(map(id, list1))) # [2779372310784, 2779372310784] print(list(map(id, list2))) # [2779372317376, 2779372633152]
可以發(fā)現(xiàn),list1 中兩個(gè)元素的對(duì)象地址值是相同的,而 list2 中兩個(gè)元素的對(duì)象地址值是不相同的。
也就是說(shuō),list1中雖然有兩個(gè)元素,但是這兩個(gè)元素的對(duì)象地址值相同,即指向同一個(gè)對(duì)象,就好比兩條繩子(變量)A,B牽著一頭牛(對(duì)象),你通過(guò)繩子 A 把牛拽過(guò)來(lái)給它掛了個(gè)鈴鐺后,你再通過(guò)繩子 B 再把牛拽過(guò)來(lái),發(fā)現(xiàn)它就是剛剛被掛鈴鐺的牛。
牛是同一頭牛,但是有兩條繩子牽著它。你無(wú)論通過(guò)哪個(gè)繩子拽牛,拽來(lái)的都是同一頭牛。
也就說(shuō),列表乘法不會(huì)生成新的牛,只是生成了牽著同一頭牛的多條繩子。
那么列表推導(dǎo)式,是會(huì)生成新的牛嗎?我們不妨再看下面代碼:
ele = [] list2 = [ele for _ in range(2)] print(list2) # [[], []] list2[0].append(0) print(list2) # [[0], [0]]
此時(shí),我們發(fā)現(xiàn) list2 發(fā)生之前相同的問(wèn)題。我們打印此時(shí) list2 內(nèi)部元素的地址值,發(fā)現(xiàn)內(nèi)部?jī)蓚€(gè)元素也指向了同一個(gè)對(duì)象。
ele = [] list2 = [ele for _ in range(2)] print(list(map(id, list2))) # [1849845272832, 1849845272832]
造成問(wèn)題出現(xiàn)的原因是,list2 的生成代碼做了如下改變:
list2 = [[] for _ in range(2)]
變?yōu)榱?/p>
ele = []
list2 = [ele for _ in range(2)]
list2 = [[] for _ in range(2)] 給了我們一種錯(cuò)覺(jué),似乎這種方式可以產(chǎn)生新的對(duì)象,但是實(shí)際上,列表推導(dǎo)式只是一種語(yǔ)法糖,它只是對(duì) for 循環(huán)的寫(xiě)法上的簡(jiǎn)化,你可以認(rèn)為列表推導(dǎo)式:
list2 = [[] for _ in range(2)]
等價(jià)于
list2 = [] for _ in range(2): list2.append([])
其中 [] 其實(shí)是一種動(dòng)作,表示:創(chuàng)建一個(gè)空列表,比如:
- list2 = [],表示創(chuàng)建一個(gè)空列表后,賦值給 list2
- list2.append([]),表示創(chuàng)建一個(gè)空列表后,追加到 list2 尾部
那么:
ele = [] list2 = [ele for _ in range(2)]
其實(shí)可以認(rèn)為等價(jià)于
ele = [] list2 = [] for _ in range(2): list2.append(ele)
上面代碼中
- ele = [],表示創(chuàng)建了一個(gè)空列表賦值給 ele
- list2.append(ele),表示將 ele的地址值 追加到 list2 尾部
這種方式本質(zhì)和列表乘法并無(wú)區(qū)別。
總結(jié)
列表乘法 [x] * n,本質(zhì)是將要元素 x 復(fù)制 n 次。
若要重復(fù)的元素 x 是不可變對(duì)象類型,則使用列表乘法后,會(huì)將元素 x 的值復(fù)制多次,最終生成的列表中的每個(gè)元素:值相同,但是不是同一個(gè)對(duì)象。
若要重復(fù)的元素 x 是可變對(duì)象類型,則使用列表乘法后,會(huì)將元素 x 的對(duì)象地址值復(fù)制多次,最終生成的列表中元素:地址值相同,都指向同一個(gè)對(duì)象。
列表推導(dǎo)式,本質(zhì)是一種語(yǔ)法糖,它只是簡(jiǎn)化了 for 循環(huán)寫(xiě)法。在代碼理解上,我們還是應(yīng)該將列表推導(dǎo)式當(dāng)成普通 for 循環(huán)來(lái)解讀。
到此這篇關(guān)于Python中列表乘法和列表推導(dǎo)式區(qū)別的文章就介紹到這了,更多相關(guān)Python列表乘法和列表推導(dǎo)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python小知識(shí)之幾種推導(dǎo)式用法示例
- Python列表推導(dǎo)式詳解
- Python進(jìn)階之列表推導(dǎo)與生成器表達(dá)式詳解
- python基礎(chǔ)操作列表推導(dǎo)式
- Python列表推導(dǎo)式的基本操作詳解
- Python使用列表推導(dǎo)式快速生成列表
- Python的列表推導(dǎo)式實(shí)例詳細(xì)解析
- Python基礎(chǔ)知識(shí)之推導(dǎo)式詳解
- Python特性之列表推導(dǎo)式和生成器表達(dá)式詳解
- python實(shí)現(xiàn)列表推導(dǎo)式與生成器
- Python 推導(dǎo)表達(dá)式的幾種方法實(shí)現(xiàn)
相關(guān)文章
python結(jié)合多線程爬取英雄聯(lián)盟皮膚(原理分析)
多線程是為了同步完成多項(xiàng)任務(wù),不是為了提高運(yùn)行效率,而是為了提高資源使用效率來(lái)提高系統(tǒng)的效率。這篇文章主要介紹了python爬取英雄聯(lián)盟皮膚結(jié)合多線程的方法,需要的朋友可以參考下2021-05-05Pytorch 實(shí)現(xiàn)凍結(jié)指定卷積層的參數(shù)
今天小編就為大家分享一篇Pytorch 實(shí)現(xiàn)凍結(jié)指定卷積層的參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01Django REST framework 單元測(cè)試實(shí)例解析
這篇文章主要介紹了Django REST framework 單元測(cè)試實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Python?Celery動(dòng)態(tài)添加定時(shí)任務(wù)生產(chǎn)實(shí)踐指南
elery是一種異步任務(wù)隊(duì)列,如果還不熟悉這個(gè)開(kāi)源軟件的請(qǐng)先看看官方文檔,快速入門(mén),下面這篇文章主要給大家介紹了關(guān)于Python?Celery動(dòng)態(tài)添加定時(shí)任務(wù)生產(chǎn)實(shí)踐的相關(guān)資料,需要的朋友可以參考下2022-08-08Python字符串轉(zhuǎn)換成浮點(diǎn)數(shù)函數(shù)分享
本文給大家分享的是一則使用Python實(shí)現(xiàn)字符串轉(zhuǎn)換成浮點(diǎn)數(shù)的代碼,主要是使用map和reduce方法來(lái)實(shí)現(xiàn),有需要的小伙伴可以參考下。2015-07-07Python reversed反轉(zhuǎn)序列并生成可迭代對(duì)象
這篇文章主要介紹了Python reversed反轉(zhuǎn)序列并生成可迭代對(duì)象,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10