Python3.6中sequence的 +=與 extend()有何區別?後者可以在tuple中使用?
本人Python萌新一枚,在看到 Fluent Python中的一個例子,有點難以理解,忘各位大大們幫小弟看看.
如圖所示:
# 在線IDE :Visualize Python, Java, JavaScript, TypeScript, and Ruby code execution
# code segment 1:
# code segment 2:
而且自己在Python的解釋器重新試了一遍 確實如此.
如果說tuple是immutable類型,只能使用 another_t=t.slice(n,m)的方式重新修改.那麼,代碼2的應該符合預期的展示,會報錯.但是為何將 += 方法改為extend()卻不會報錯?
而且 我從文檔中查到:
也就是說 extend()方法和 __iadd__() 這種dunder方法是一致的.既然如此 為何後者會報錯,而前者卻不會報錯?
官方文檔也是個好東西,比如這個問題其實就在FAQ里
Programming FAQ - Python 3.6.2 documentation
——————————————————
其實原因很簡單,兩個操作並不一樣。語義都是不同的。list和tuple比較特殊,其它object或許更容易看出來,但是如果你需要弄明白list和tuple這裡的情況,其實需要看解釋器源碼。
對於第一個寫法,使用的a[2].extend(),對解釋器而言發生了如下事情:
1. 對a這個tuple的getitem
2.調用了extend方法
都沒有衝突所以正常進行。
對於+=,則有些不一樣:
1. 對a進行getitem(2)
2. 對結果調用InplaceConcat,進而調用PyListObject的list_concat並將結果通過a的setitem放回去
而這裡有兩個問題,直接報錯的是setitem,但更深層的問題是,list_concat會新建一個list……儘管由於計數GC的存在,他還會是同一個id,但實際上已經不是同一個對象了(其實list是特例)。所以這裡才存在一個賦值操作,所以才會有setitem,才會報錯。
這個的確是有個陷阱在裡面的,變數的+=都知道是怎麼回事,問題在於索引表達式的+=實際等於三步:
a[i] += b
等效於
t = a[i]
t += b
a[i] = t
而extend只相當於前兩步
tuple中的元素是不允許重新賦值,但是這些元素所引用的對象,則是可以原地修改的(前提對象類型是可修改的)。
調用 extend 是原地修改,修改的是tuple元素所引用的對象。
而 += 則是重新賦值,要直接修改 tuple 元素,當然就要報錯了。
關於 __iadd__:x += y 相當於 x = x.__iadd__(y),而不是直接的 x.__iadd__(y)。可能是要保持賦值語義吧。
Overriding amp;quot;+=amp;quot; in Python? (__iadd__() method)
3. Data model - Python 3.6.2 documentation
推薦閱讀:
※Python 常用的標準庫以及第三方庫有哪些?
※python有哪些數據分析和數據展現的模塊可以用?
※下載了rqalpha源代碼,不知道如何用ipython直接在源代碼中調試運行。?
※如何制定python學習計劃?
※如何閱讀goagent的代碼?