《流暢的python》讀書筆記(7)

2021-10-02 00:27:22 字數 2387 閱讀 3417

增量賦值運算子 += 和 *= 的表現取決於它們的第乙個操作物件+= 背後的特殊方法是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...