主要參考的是Github上的一個項目:https://github.com/jackfrued/Python-100-Days
文章主要是對該項目中的內容進行學習 穿插一點自己的學習想法等內容~
嵌套列表
names = ['關羽', '張飛', '趙雲', '馬超', '黃忠']
courses = ['語文', '數學', '英語']
# 錄入五個學生三門課程的成績
# 錯誤 - 參考http://pythontutor.com/visualize.html#mode=edit
# scores = [[None] * len(courses)] * len(names)
scores = [[None] * len(courses) for _ in range(len(names))]
for row, name in enumerate(names):
for col, course in enumerate(courses):
scores[row][col] = float(input(f'請輸入{name}的{course}成績: '))
print(scores)
該代碼的目的是為了構造一個names做行 courses做列的表格來記錄五個人的三門功課成績。
實際上即為構造一個5 × 3的二維數組。直接用循環造一個空的往里邊填數字也不是不行-_-
列表嵌套存在的意義就是簡化用循環去構造一個空列表的繁瑣代碼。
錯誤代碼
首先來看一下文中寫的那段錯誤的代碼~
scores = [[None] * len(courses)] * len(names)
自我分析
首先是一個空列表重復 len(courses) 次構成一個新列表,結果就是[[], [], []]
上述生成的列表再重復 len(names) 次,結果就是[[], [], []], [[], [], []], [[], [], []], [[], [], []], [[], [], []]?
是不是這個樣子哇.....
結果運行
只運行這三行代碼,結果顯示scores的內容如下:
[[None, None, None], [[None, None, None], [[None, None, None], [[None, None, None], [[None, None, None]]
None
且來科普一下None
None是一個特殊的常量,N必須大寫。它不表示0,不表示空字符串,表示沒有值(空值),數據類型是NoneType
空值與空對象不同,空值和占位符感覺差不多,知道這里應該有東西 但具體是什么不知道。空對象就是只定義了類型,里邊什么都不知道,有幾個等信息都不知道。
常用於assert、判斷以及函數無返回值的情況。例如使用print函數輸出數據,函數的返回值就是None。在不得不設置返回值的地方起到了一個占位作用。
Python函數中不寫返回值,默認返回None;最后只寫了return 同理。
揭秘
將分析語句變成兩個語句去執行
a = [[None] * len(courses)]
b = a * * len(names)
你會發現更改會對a和b同時生效,建立索引的時候你的列表行索引並沒有太大用處。操作就是找到列 然后修改那一列的所有元素。
實際上就是修改了列表a 然后重復列表a 表現在b中
所以這樣的嵌套是失敗的,最后你只能得到所有人的分數都和黃忠一樣。
猜測應該是先構造了一個1 * 3 的列表,然后重復了5次,最后外邊加了一個框 像二維數組一樣【實際上並不是】
從下邊的這張圖中就可以明顯地看出來原因!證明我們的推測!
正確代碼
scores = [[None] * len(courses) for _ in range(len(names))]
自我分析
一看外邊的框就知道這是一個列表嵌套,外邊是一個數組,里邊是一個數組。
這樣采用for循環去重復 就解除了列表之間的聯系,每個都不一樣,所以可以單獨編輯不受影響。
總結反思
http://pythontutor.com/visualize.html#mode=display
上述這個鏈接可以看到代碼執行時內存空間及值的分配情況,直觀看出來錯誤原因出現在哪里!
使用列表嵌套時可以先寫個簡單的小例子測試一下
【當然還是知道原理最重要】