Python 如何正確初始化二維陣列
最近的開發刷題需求中,遇到需要宣告二維陣列的情境,卻發現資料的存取結果與預期不符。
資料怎麼塞都不對…🥹
在這篇文章中,我將分享如何正確地初始化 Python 二維陣列。
問題
故事的開頭是這樣的,一切就是這麼簡潔這麼美,如此的 Pythonic ☺️1
test_list = [[]] * 3
但結果發現無論我在哪個維度塞資料時,都發現所有的子陣列都會出現相同的結果。1
2
3
4
5test_list = [[]] * 3
test_list[0].append(0)
for l in test_list:
print(l)
執行結果1
2
3[0]
[0]
[0]
WTF?
為了探究這個問題,我使用 id()
函數列出了每個子陣列的物件 ID。
id(object)
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory.https://docs.python.org/3/library/functions.html#id
1 | test_list = [[]] * 3 |
結果發現1
2
34307825408
4307825408
4307825408
Why? 到底是為什麼?
結論
經過一番追尋之後,終於在 Python 官方文件 Sequence Types 找到答案。
其中,有一段很重要的提醒。
Note that items in the sequence s are not copied; they are referenced multiple times. This often haunts new Python programmers;
這段話解釋了為什麼我們之前看到所有子陣列都有相同的 ID —— 它們實際上是指向同一個物件的多個參考。
同時官方文件也提供了發生相同問題的程式碼。1
2
3
4
5
6lists = [[]] * 3
lists
[[], [], []]
lists[0].append(3)
lists
[[3], [3], [3]]
同時也推薦各位用以下方式初始化。1
2
3
4
5
6lists = [[] for i in range(3)]
lists[0].append(3)
lists[1].append(5)
lists[2].append(7)
lists
[[3], [5], [7]]
如果你需要建立特定大小的二維陣列(y 列 x 行),可以這樣做:1
2
3
4
5
6
7y = 3
x = 4
test_list = [[0] * x for _ in range(y)]
# test_list[y][x]
test_list[y - 1][x - 1] = 1
而官方也出了一篇 FAQ 專門講這件事
How do I create a multidimensional list?
追尋至此終於宣告破案…