Python列表嵌套常見坑點(diǎn)及解決方案
1.嵌套列表
Python中有一種內(nèi)置的數(shù)據(jù)類型叫列表(list),它是一種容器,可以用來承載其他的對象(準(zhǔn)確的說是其他對象的引用),列表中的對象可以稱為列表的元素,很明顯我們可以把列表作為列表中的元素,這就是所謂的嵌套列表。
嵌套列表可以模擬出現(xiàn)實(shí)中的表格、矩陣、2D游戲的地圖(如植物大戰(zhàn)僵尸的花園)、棋盤(如國際象棋、黑白棋)等。
2.識別坑點(diǎn)
在使用嵌套的列表時(shí)要小心,否則很可能遭遇非常尷尬的情況,下面是一個(gè)小例子。
def main(): names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠'] subjs = ['語文', '數(shù)學(xué)', '英語'] scores = [[0] * 3] * 5 for row, name in enumerate(names): print('請輸入%s的成績' % name) for col, subj in enumerate(subjs): scores[row][col] = float(input(subj + ': ')) print(scores)if __name__ == '__main__': main()
names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠']
subjs = ['語文', '數(shù)學(xué)', '英語']
scores = [[0] * 3] * 5
for row, name in enumerate(names):
print('請輸入%s的成績' % name)
for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': '))
print(scores)
if __name__ == '__main__':
main()
我們希望錄入5個(gè)學(xué)生3門課程的成績,于是定義了一個(gè)有5個(gè)元素的列表,而列表中的每個(gè)元素又是一個(gè)由3個(gè)元素構(gòu)成的列表,這樣一個(gè)列表的列表剛好跟一個(gè)表格是一致的,相當(dāng)于有5行3列。
接下來我們通過嵌套的for-in循環(huán)輸入每個(gè)學(xué)生3門課程的成績。程序執(zhí)行完成后我們發(fā)現(xiàn),每個(gè)學(xué)生3門課程的成績是一模一樣的(尷尬),而且就是最后錄入的那個(gè)學(xué)生的成績。
3。區(qū)分兩個(gè)概念
要想把這個(gè)坑填平,我們首先要區(qū)分對象和對象的引用這兩個(gè)概念,而要區(qū)分這兩個(gè)概念,還得先說說內(nèi)存中的棧和堆。
我們經(jīng)常會聽人說起“堆?!边@個(gè)詞,但實(shí)際上“堆”和“?!笔莾蓚€(gè)不同的概念。眾所周知,一個(gè)程序運(yùn)行時(shí)需要占用一些內(nèi)存空間來存儲數(shù)據(jù)和代碼,那么這些內(nèi)存從邏輯上又可以做進(jìn)一步的劃分。
對底層語言(如C語言)有所了解的程序員大都知道,程序中可以使用的內(nèi)存從邏輯上可以為五個(gè)部分,按照地址從高到低依次是:棧(stack)、堆(heap)、數(shù)據(jù)段(data segment)、只讀數(shù)據(jù)段(static area)和代碼段(code segment)。
棧用來存儲局部、臨時(shí)變量,以及函數(shù)調(diào)用時(shí)保存現(xiàn)場和恢復(fù)現(xiàn)場需要用到的數(shù)據(jù),這部分內(nèi)存在代碼塊開始執(zhí)行時(shí)自動(dòng)分配,代碼塊執(zhí)行結(jié)束時(shí)自動(dòng)釋放,通常由編譯器自動(dòng)管理。
堆的大小不固定,可以動(dòng)態(tài)的分配和回收,因此如果程序中有大量的數(shù)據(jù)需要處理,這些數(shù)據(jù)通常都放在堆上,如果堆空間沒有正確的被釋放會引發(fā)內(nèi)存泄露的問題,而像Python、Java等編程語言都使用了垃圾回收機(jī)制來實(shí)現(xiàn)自動(dòng)化的內(nèi)存管理(自動(dòng)回收不再使用的堆空間)。
4。小例子
所以,下面的代碼中,變量a并不是真正的對象,它是對象的引用,相當(dāng)于記錄了對象在堆空間的地址,通過這個(gè)地址我們可以訪問到對應(yīng)的對象。
a = object()b = ['apple', 'pitaya', 'grape']
b = ['apple', 'pitaya', 'grape']
同理,變量b是列表容器的引用,它引用了堆空間上的列表容器,而列表容器中并沒有保存真正的對象,它保存的也僅僅是對象的引用。
知道了這一點(diǎn),我們可以回過頭看看剛才的程序,我們對列表進(jìn)行[[0]* 3] * 5操作時(shí),僅僅是將[0, 0, 0] 這個(gè)列表的地址進(jìn)行了復(fù)制,并沒有創(chuàng)建新的列表對象。
所以,容器中雖然有5個(gè)元素,但是這5個(gè)元素引用了同一個(gè)列表對象。這一點(diǎn)可以通過id函數(shù)檢查scores[0]和scores[1]的地址得到證實(shí)。在此我們舉一個(gè)小例子,讀者朋友們可以敲一敲加深印象。
a = [[0]*3]*5id(a[0])id(a[1])# id相等
id(a[1])
# id相等
5。正確代碼
所以,正確的代碼應(yīng)該按照如下的方式進(jìn)行修改。
def main(): names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠'] subjs = ['語文', '數(shù)學(xué)', '英語'] scores = [[]] * 5 for row, name in enumerate(names): print('請輸入%s的成績' % name) scores[row] = [0] * 3 #變?yōu)椴辉偾短? for col, subj in enumerate(subjs): scores[row][col] = float(input(subj + ': ')) print(scores)if __name__ == '__main__': main()'關(guān)羽', '張飛', '趙云', '馬超', '黃忠']
subjs = ['語文', '數(shù)學(xué)', '英語']
scores = [[]] * 5
for row, name in enumerate(names):
print('請輸入%s的成績' % name)
scores[row] = [0] * 3 #變?yōu)椴辉偾短?
for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': '))
print(scores)
if __name__ == '__main__':
main()
或者
def main(): names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠'] subjs = ['語文', '數(shù)學(xué)', '英語'] scores = [[0] * 3 for _ in range(5)] for row, name in enumerate(names): print('請輸入%s的成績' % name) scores[row] = [0] * 3 for col, subj in enumerate(subjs): scores[row][col] = float(input(subj + ': ')) print(scores)if __name__ == '__main__': main()
names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠']
subjs = ['語文', '數(shù)學(xué)', '英語']
scores = [[0] * 3 for _ in range(5)]
for row, name in enumerate(names):
print('請輸入%s的成績' % name)
scores[row] = [0] * 3
for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': '))
print(scores)
if __name__ == '__main__':
main()
以上就是使用嵌套列表需要注意的問題及解決措施,希望大家多多總結(jié),以此避免在使用嵌套列表或者復(fù)制對象時(shí)可能遇到的坑。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
opencv python 圖像輪廓/檢測輪廓/繪制輪廓的方法
這篇文章主要介紹了opencv python 圖像輪廓/檢測輪廓/繪制輪廓的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
Python對字符串實(shí)現(xiàn)去重操作的方法示例
字符串去重是python中字符串操作常見的一個(gè)需求,最近在工作中就又遇到了,所以下面這篇文章主要給大家介紹了關(guān)于Python對字符串實(shí)現(xiàn)去重操作的相關(guān)資料,文中給出了詳細(xì)的介紹,需要的朋友可以參考借鑒,下面來一起看看吧。2017-08-08
Python3進(jìn)行表格數(shù)據(jù)處理的示例詳解
數(shù)據(jù)處理是一個(gè)當(dāng)下非常熱門的研究方向,通過對于大型實(shí)際場景中的數(shù)據(jù)進(jìn)行建模,可以用于預(yù)測下一階段可能出現(xiàn)的情況。本文就來聊聊Python3進(jìn)行表格數(shù)據(jù)處理的相關(guān)操作,需要的可以參考一下2023-03-03
Python基礎(chǔ)語言學(xué)習(xí)筆記總結(jié)(精華)
給大家分享一篇關(guān)于Python基礎(chǔ)學(xué)習(xí)內(nèi)容的學(xué)習(xí)筆記整理總結(jié)篇,里面匯集了學(xué)習(xí)Python基礎(chǔ)語言的難點(diǎn)和技巧,分享給大家。2017-11-11
flask使用session保存登錄狀態(tài)及攔截未登錄請求代碼
這篇文章主要介紹了flask使用session保存登錄狀態(tài)及攔截未登錄請求代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
詳解centos7+django+python3+mysql+阿里云部署項(xiàng)目全流程
這篇文章主要介紹了詳解centos7+django+python3+mysql+阿里云部署項(xiàng)目全流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11

