首先,不用解釋器,腦補一下下面這段代碼的結果是什麼
1 2 3 4 5 6 7 8 |
def add(lst1,lst2): for i in xrange(len(lst1)): lst1[i]+=lst2[i] a=[[0]*3]*3 add(a[0],[1,0,0]) add(a[1],[0,1,0]) print a[1] |
有沒有娃兒和我一樣覺得是[0,1,0]的?
實際上結果出人意料地是[1,1,0]
WTF!昨天晚上我想了三宿都沒明白Σ(`д′*ノ)ノ 後來吃了一個橙子終於想通了
a=[[0]*3]*3這句話來將a賦值成 [[0,0,0],[0,0,0],[0,0,0]],然而python似乎是這樣賦值的:
為了驗證這個猜想我們用內置函數id來打印內存地址(僅對cpython而言)
1 2 3 4 5 6 |
>>> id(a[0]) 38025256 >>> id(a[1]) 38025256 >>> id(a[2]) 38025256 |
這證明了我們的猜想。
那麼如果我用下面這句話來初始化a呢?
1 |
a=[[0]*3 for i in range(3)] |
這次直接看id:
1 2 3 4 5 6 |
>>> id(a[0]) 38056704 >>> id(a[1]) 38056744 >>> id(a[2]) 33504712 |
不一樣了吧。可見使用列表推導式時,每次都會重新計算一次[0,0,0]的值(在這個例子中它不隨i變化),而不會去引用之前的結果;或者說,*運算符作用於列表時產生n個對原對象的引用,而不是真正的複製
還有個有趣的現象
1 2 3 4 5 |
>>> a=1 >>> id(a) 38176416 >>> id(1) 38176416 |
真特么摳門,真不知道cpython的內存回收是怎麼做的,有空去看看源碼(* ̄︶ ̄)y