增量賦值運算子 += 和 *= 的表現取決於它們的第乙個操作物件+= 背後的特殊方法是iadd(用於「就地加法」)但是如果乙個類沒有實現這個方法的話,python 會退一步呼叫 __add__如果 a 實現了iadd方法,就會呼叫這個方法。
同時對可變序列(例如list、bytearray 和 array.array)來說,a 會就地改動,就像呼叫了 a.extend(b)一樣。但是如果 a 沒有實現iadd的話,a += b 這個表示式的效果就變得跟 a = a+ b 一樣了:首先計算 a + b,得到乙個新的物件,然後賦值給 a。
也就是說,在這個表示式中,變數名會不會被關聯到新的物件,完全取決於這個型別有沒有實現iadd這個方法。
總體來講,可變序列一般都實現了iadd方法,因此 += 是就地加法。而不可變序列根本就不支援這個操作,對這個方法的實現也就無從談起。上面所說的這些關於 += 的概念也適用於 *=,不同的是,後者相對應的是imul
乙個列子
# *= 在可變和不可變序列上的作用
# 列表是乙個可變序列
l =[1,
2,3]
print(id
(l))
# 1685058314824
l *=
2print
(l)# [1, 2, 3, 1, 2, 3]
print(id
(l))
# 1685058314824
# 可以發現 對於可變序列 在使用*=運算子後 其id不變
# 元組是不可變的序列
x =(1,
2,3)
print(id
(x))
# 1364365308120
x *=
2print
(x)# (1, 2, 3, 1, 2, 3)
print(id
(x))
# 1364363843528
# 對於不可變的序列進行 *= 之後 新的物件被建立了
但是 注意:str 是乙個例外,因為對字串做 += 實在是太普遍了,所以 cpython 對它做了優化。
為 str 初始化記憶體的時候,程式會為它留出額外的可擴充套件空間,因此進行增量操作的時候,
並不會涉及複製原有字串到新位置這類操作
乙個關於+=的謎題
看到這個例子我也很懵圈。
且看書中闡述
t = (1, 2, [30, 40])
t[2] += [50,60]
備選答案:
a. t 變成 (1, 2, [30, 40, 50, 60])。
b. 因為 tuple 不支援對它的元素賦值,所以會丟擲 typeerror 異常。
c. 以上兩個都不是。
d. a 和 b 都是對的。
首先書中的** 在pycharm是執行不出來的。 在控制台就出現了這種神奇的情況
>>> t = (1,2,[3,4])
>>> t[2] += [5,6]
traceback (most recent call last):
file 「」, line 1, in
typeerror: 『tuple』 object does not support item assignment
>>> t
(1, 2, [3, 4, 5, 6])
所以答案是 d
謎題解釋
示例 2-16 s[a] = b 背後的位元組碼
>>> dis.dis(『s[a] += b』)
1 0 load_name 0(s)
3 load_name 1(a)
6 dup_top_two
7 binary_subscr 將 s[a] 的值存入 tos(top of stack,棧的頂端)
8 load_name 2(b)
11 inplace_add 計算 tos += b。這一步能夠完成,是因為 tos 指向的是乙個可變物件(也就是[30,40])
12 rot_three
13 store_subscr s[a] = tos 賦值。這一步失敗,是因為 s 是不可變的元組(元組t)
14 load_const 0(none)
17 return_value
所以呢 就完成了對列表的賦值 但是到 元組賦值處報錯,但列表中的內容還是儲存了
作者得到的教訓,當然咱也應該得到
不要把可變物件放在元組裡面
增量賦值不是乙個原子操作。我們剛才也看到了,它雖然丟擲了異常,但還是完成了
操作檢視 python 的位元組碼並不難,而且它對我們了解**背後的執行機制很有幫助
《流暢的Python》讀書筆記
第1章 python資料模型 通過實現特殊方法,自定義資料型別可以表現得和內建型別一樣 repr 方便除錯和記錄日誌,str 方便使用者看 序列資料型別特殊方法使用最多 第2章 序列構成的陣列 系列型別可分為 可變和不可變 扁平序列和容器序列 列表推導生成器表示式提供了靈活構建和初始化序列的方式 元...
流暢的python讀書筆記
1.雖然也可以用列表推導來初始化元組 陣列或其他序列型別,但是生成器表示式是更好的選擇。這是因為生成器表示式背後遵守了迭代器協議,可以逐個地產出元素,而不是先建立乙個完整的列表,然後再把這個列表傳遞到某個建構函式裡。前面那種方式顯然能夠節省記憶體。生成器表示式的語法跟列表推導差不多,只不過把方括號換...
《流暢的Python》讀書筆記(三)
country code my dict.setdefault key,使用 collections.defaultdict import collections index collections.defaultdict list index hunan changsha index defaul...