日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

序列赋值引发的Python列表陷进

發布時間:2025/3/20 python 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 序列赋值引发的Python列表陷进 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

序列賦值是Python默認操作,如果使用不當,有可能會掉入語法陷阱。

+

+是指把兩個序列的元素拼接在一起。通常+號兩側的序列由相同類型的數據所構成,在拼接的過程中,兩個被操作的序列都不會被修改,Python會新建一個包含同樣類型數據的序列作為拼接的結果。比如:

a = [1] b = [2] c = a + b print(a, b, c) print(id(a), id(b), id(c))

結果為:

[1] [2] [1, 2] 2409610524480 2409610523520 2409610523648

*

如果想要把一個序列復制幾份然后再拼接起來,更快捷的做法是把這個序列乘以一個整數。同樣,這個操作會產生一個新序列:

>>> l = [1] >>> l * 5 [1, 1, 1, 1, 1] >>> 5 * "a" 'aaaaa'

+和*都遵循這個規律,不修改原有的操作對象,而是構建一個全新的序列。

列表套列表的陷進

猜猜這個結果會是啥:

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:531509025 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' x = ["x"] my_list = [x] * 3 print(my_list) # [['x'], ['x'], ['x']] x2 = my_list[2] x2[0] = "y" print(my_list)

講道理,應該是[[‘x’], [‘x’], [‘y’]],但是錯了,實際是:

[['y'], ['y'], ['y']]

Unbelievable!給my_list的最后一個元素的列表賦值,結果所有三個元素的列表都被賦值了!這反映出my_list這三個元素不是3個列表,而是3個列表引用,指向了同一個相同的列表。相當于:

x = ["x"] my_list = [] for i in range(3): my_list.append(x) # 追加相同對象 x2 = my_list[2] x2[0] = "y" print(my_list) # [['y'], ['y'], ['y']]

每次都追加了同一個對象到my_list。如果想生成3個不同列表,那么需要在每次迭代中新建列表:

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:531509025 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' my_list = [] for i in range(3): x = ["x"] # 新建列表 my_list.append(x) x2 = my_list[2] x2[0] = "y" print(my_list) # [['x'], ['x'], ['y']]

這樣就符合預期了。可以用列表推導簡化代碼:

x = ["x"] my_list = [x for i range(3)] x2 = my_list[2] x2[0] = "y" print(my_list) # [['x'], ['x'], ['y']]

教訓:

新建列表中的列表,使用列表推導,不要使用*運算符。

如果a * n這個語句中,序列a里的元素是對其他可變對象的引用的話,就需要格外注意了,這可能不是你想要的效果。

+=

a += b雖然意思是a = a + b,但是它背后的特殊方法是__iadd__,如果一個類沒有實現這個方法的話,Python才會退一步調用__add__。__iadd__方法會直接在原對象中追加,__add__方法會先生成新對象再賦值。

*=

+=的這些概念也適用于*=,只是后者對應的是__imul__。追加還是新對象,在作用到可變序列和不可變序列時效果明顯,示例:

# 可變序列,追加 >>> l = [1, 2, 3] >>> id(l) 2135319475136 >>> l *= 2 >>> l [1, 2, 3, 1, 2, 3] >>> id(l) 2135319475136 # id一樣 # 不可變序列,新對象 >>> t = (1, 2, 3) >>> id(t) 2135322139520 >>> t *= 2 >>> id(t) 2135321695424 # id不一樣

元組套列表的陷進

>>> t = (1, 2, [30, 40]) >>> t[2] += [50, 60]

猜猜會發生下面4種情況中的哪一種?a.t變成(1, 2, [30, 40, 50, 60])b.因為tuple不支持對它的元素賦值,所以會拋出TypeError異常c.以上兩個都不是d.a和b都是對的因為元組不能賦值,所以我會毫不猶豫的選擇b。但實際上答案是d!a和b都是對的,既會賦值成功,也會報錯:

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:531509025 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' >>> t = (1, 2, [30, 40]) >>> t[2] += [50, 60] Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> t (1, 2, [30, 40, 50, 60])

Oh No!為什么?
一、賦值成功,因為t[2]指向的是一個可變對象(列表[30, 40]),可變對象是能賦值的。

二、報錯,因為可變對象賦值給了不可變對象(元組t),不可變對象不能賦值。

寫成t[2].extend([50, 60])能避免這個異常。

教訓:

  • 不要把可變對象放在元組里面。
  • +=不是一個原子操作,雖然拋出了異常,但還是完成了操作。

這位巴西作者說到,在他15年的Python生涯中,他還沒見過誰在這個地方吃過虧。

小結

本文分別介紹了+、*和列表套列表的陷阱,+=、*=和元組套列表的陷阱,并分別得出了教訓。這是動態語言的弊端,在運行后才能知道有沒有類型錯誤,只能積累代碼經驗來避免。魚與熊掌不可兼得,在享受Python語法簡潔的便利同時,也得付出運行報錯排查麻煩的代價。

總結

以上是生活随笔為你收集整理的序列赋值引发的Python列表陷进的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。