摘要:不可變對象不允許對自身內容進行修改。因為他們說到不可變對象時用的是賦值,而說到可變對象又用了的索引等方法,這根本是兩碼事。基于這一設定,兩者在功能上的最大區別就是不可變對象可以作為字典的鍵,而可變對象不行。
前陣子我們聊了下函數的參數傳遞以及變量賦值的一些內容:關于函數參數傳遞,80%人都錯了
簡單回顧下要點:
1. Python 中的變量不是裝有對象的“ 容器 ”,而是貼在對象上的“ 標簽 ”。
2. 參數傳遞相當于一次 賦值 :多貼了一個標簽。
3. 至于在函數內部對參數的修改是否會影響到外部變量的值,取決于你怎樣修改:如果是重新賦值就不會,如果是修改對象自身內容則會。
講到這里就有個常被提及的概念:
可變對象和不可變對象
在 Python 中,
可變對象 包括 list、dict、set、自定義類型 等;
不可變對象 包括 int、float、bool、str、tuple 等。
不可變對象不允許對自身內容進行修改。如果我們對一個不可變對象進行賦值,實際上是生成一個新對象,再讓變量指向這個對象。哪怕這個對象簡單到只是數字 0 和 1:
a = 0 print("a", id(a)) a = 1 print("a", id(a))
輸出:
a 4463151440 a 4463151472
因為對象不可變,所以為了提高效率,Python 會使用一些公用的對象:
a = 1 print("a", id(a)) b = 1 print("b", id(b)) print(a == b) print(a is b) c = "hello world" print("c", id(c)) d = "hello world" print("d", id(d)) print(c == d) print(c is d)
輸出:
a 4423761776 b 4423761776 True True c 4430180912 d 4430180912 True True
這里順便提一下 is 這個操作符。它和 == 的區別在于:== 只判斷“值”是不是相等,而 is 則判斷是否為同一個對象,也就是地址一致。比如:
a = 2 b = 2.0 print(a == b) print(a is b)
輸出:
True False
而可變對象則可以對自身內容進行修改,如:
m = [1, 2, 3] print("m", m, id(m)) m[1] = 4 print("m", m, id(m)) m.append(5) print("m", m, id(m))
輸出:
m [1, 2, 3] 4536815752 m [1, 4, 3] 4536815752 m [1, 4, 3, 5] 4536815752
可以看到,雖然 m 的值發生了變化,但是地址沒變,還是原來那個 m。
上次我也說到,很多的教程都在用可變和不可變來談論賦值和參數傳遞,我覺得這很不好。因為他們說到不可變對象時用的是賦值,而說到可變對象又用了 list 的索引、apeend 等方法,這根本是兩碼事。如果大家都是賦值,那么無論是否可變,效果都是一樣的:
m = [1, 2, 3] print("m", m, id(m)) m = [4, 5, 6] print("m", m, id(m))
輸出
m [1, 2, 3] 4329894024 m [4, 5, 6] 4329910856
所以理解了 Python 的賦值原理,就明白這與是否可變無關。而可變對象于不可變對象本身的不同僅在于一個可以修改變量的值,而另一個不允許。
基于這一設定,兩者在功能上的最大區別就是: 不可變對象可以作為字典 dict 的鍵 key ,而可變對象不行。比如 list 不能作為字典的鍵,但 tuple 可以。
另外,明白了可變與不可變的區別,一些方法的效果也就自然理解了:
s = "abc" s2 = s.replace("b", "d") print("s", s) print("s2", s2) m = [1, 2, 3] m2 = m.reverse() print("m", m) print("m2", m2)
輸出:
s abc s2 adc m [3, 2, 1] m2 None
因為 str 是不可變對象,所以它的方法如 replace、strip、upper 都不可能修改原對象, 只會返回一個新對象 ,比如重新賦值才可以。而 list 是可變對象,它的方法如 reverse、sort、append,都是 在原有對象上直接修改 ,無返回值。
不過,有個特殊情況需要注意:
m = [1, 2, 3] print("m", m, id(m)) m += [4] print("m", m, id(m)) m = m + [5] print("m", m, id(m))
輸出
m [1, 2, 3] 4494164104 m [1, 2, 3, 4] 4494164104 m [1, 2, 3, 4, 5] 4494181128
m = m + 和 m += 雖然是一樣的結果,但 m 指向的對象卻發生了變化。原因在于,前者是做了賦值操作,而后者其實是調用的 __iadd__ 方法。
如果我們就是需要產生一個 list 對象的副本,可以通過 [:]:
m = [1, 2, 3] print("m", m, id(m)) n = m[:] print("n", n, id(n)) n[1] = 4 print("m", m) print("n", n)
這樣對 n 的修改便不再會影響到 m,因為它們已不是同一個對象。
那么如果是這樣呢:
m = [1, 2, [3]] n = m[:] n[1] = 4 n[2][0] = 5 print(m)
猜一猜 m 的結果是什么?
[1, 2, [3]]
[1, 4, [3]]
[1, 2, [5]]
[1, 4, [5]]
其它結果
再去 Python 里執行下看看輸出,是不是和預期一樣,想想為什么?這個牽涉到淺拷貝、深拷貝的概念,我們下次再聊。
════
其他文章及回答:
如何自學Python | 新手引導 | 精選Python問答 | Python單詞表 | 區塊鏈 | 人工智能 | 雙11 | 嘻哈 | 爬蟲 | 排序算法 | 我用Python | 高考 | 世界杯 | 競猜 | requests
歡迎搜索及關注: Crossin的編程教室
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42499.html
摘要:中的可變與不可變對象中的所有東西都是一個對象。和內置函數以整數形式返回對象的標識。更改可變對象很便宜。不可變的例外并非所有的不可變對象都是不可變的。所以引用該對象的變量不會改變,但對象本身正在改變,但僅在函數范圍內。 Python中的可變與不可變對象 Python中的所有東西都是一個對象。每個Python新手都應該學習的是,Python中的所有對象都可以是可變的或不可變的。showIm...
摘要:變量在我們的編程中是最基礎的概念,它就相當于我們蓋大樓用的磚塊一樣不可或缺。理解變量的運行方式至關重要。雖然他們的食物是一樣的。但是,像這樣這樣并沒有新建對象,而是將的引用傳遞給了,他們都指向一個對象。這個就是的垃圾回收機制。 變量在我們的編程中是最基礎的概念,它就相當于我們蓋大樓用的磚塊一樣不可或缺。理解變量...
不可變對象 如果一個對象的狀態在構造后不能改變,則該對象被認為是不可變的,對不可變對象的最大依賴被廣泛認為是一種創建簡單、可靠代碼的合理策略。 不可變對象在并發應用程序中特別有用,由于它們不能改變狀態,因此它們不會被線程干擾破壞或在不一致的狀態下觀察。 程序員通常不愿意使用不可變對象,因為他們擔心創建新對象的成本而不是就地更新對象的成本,對象創建的影響經常被高估,并且可以通過與不可變對象相關聯的一...
摘要:不要疑惑,告訴你答案這個代表正負號的正。雖然一點技術含量沒有,但是你要懂序列也許叫可迭代對象更為合適,但是我喜歡叫序列。 數據結構 可變類型與不可變類型(重頭戲) 基操: 可變類型:[], {} # 可增刪改 查 不可變類型: int float str () # 無法增刪改, 只可查 升操: + 與...
閱讀 1181·2021-09-22 15:24
閱讀 2285·2019-08-30 15:44
閱讀 2615·2019-08-30 10:55
閱讀 3355·2019-08-29 13:25
閱讀 1639·2019-08-29 13:09
閱讀 1391·2019-08-26 14:05
閱讀 1379·2019-08-26 13:58
閱讀 1985·2019-08-26 11:57