摘要:不可變對(duì)象包括,,,,等,可變對(duì)象包括,,等。在中,賦值的過程僅僅是創(chuàng)建一個(gè)某個(gè)值的對(duì)象將變量名指向引用這個(gè)對(duì)象。這就像語言中指針的概念,只不過更靈活地是中的變量隨時(shí)可以指向其它對(duì)象不分類型,其它變量也可以指向這一對(duì)象。
項(xiàng)目地址:https://git.io/pytips
Python 中的對(duì)象分為兩種:可變對(duì)象(mutable)和不可變對(duì)象(immutable)。不可變對(duì)象包括int,float,long,str,tuple等,可變對(duì)象包括list,set,dict等。在 Python 中,賦值(assignment, =)的過程僅僅是:
創(chuàng)建一個(gè)(某個(gè)值的)對(duì)象;
將變量名指向(引用)這個(gè)對(duì)象。
這就像 C 語言中指針的概念,只不過更靈活地是 Python 中的變量隨時(shí)可以指向其它對(duì)象(不分類型),其它變量也可以指向這一對(duì)象。如果這一對(duì)象是可變的,那么對(duì)其中一個(gè)引用變量的改變會(huì)影響其它變量:
lst = [1, 2, 3] s = lst s.pop() print(lst) d = {"a": 0} e = d e["b"] = 1 print(d)
[1, 2] {"b": 1, "a": 0}
如果你不是刻意想要這樣做(實(shí)際也很少會(huì)要這樣操作),那么就可能導(dǎo)致一些意想不到的錯(cuò)誤(尤其是在傳遞參數(shù)給函數(shù)的時(shí)候)。為了解決這一麻煩,最簡單的方法就是不直接變量指向現(xiàn)有的對(duì)象,而是生成一份新的 copy 賦值給新的變量,有很多種語法可以實(shí)現(xiàn):
lst = [1,2,3] llst = [lst, lst[:], lst.copy(), [*lst]] # invalid in 2.7 for i, v in enumerate(llst): v.append("#{}".format(i)) print(lst) d = {"a": 0} dd = [d, d.copy(), {**d}] # invalid in 2.7 for i, v in enumerate(dd): v["dd"] = "#{}".format(i) print(d)
[1, 2, 3, "#0"] {"dd": "#0", "a": 0}deep vs shallow
上面給出的這些 copy 的例子比較簡單,都沒有嵌套的情況出現(xiàn),如果這里的可變對(duì)象中還包含其它可變對(duì)象,結(jié)果會(huì)怎樣呢:
lst = [0, 1, [2, 3]] llst = [lst, lst[:], lst.copy(), [*lst]] for i, v in enumerate(llst): v[2].append("#{}".format(i)) print(lst) d = {"a": {"b": [0]}} dd = [d, d.copy(), {**d}] for i, v in enumerate(dd): v["a"]["b"].append("#{}".format(i)) print(d)
[0, 1, [2, 3, "#0", "#1", "#2", "#3"]] {"a": {"b": [0, "#0", "#1", "#2"]}}
這些 copy 的方法稱為淺拷貝(shallow copy),它相比直接賦值更進(jìn)了一步生成了新的對(duì)象,但是對(duì)于嵌套的對(duì)象仍然采用了賦值的方法來創(chuàng)建;如果要再進(jìn)一步,則需要深拷貝(deep copy),由標(biāo)準(zhǔn)庫 copy 提供:
from copy import deepcopy lst = [0, 1, [2, 3]] lst2 = deepcopy(lst) lst2[2].append(4) print(lst2) print(lst) d = {"a": {"b": [0]}} d2 = deepcopy(d) d2["a"]["b"].append(1) print(d2) print(d)
[0, 1, [2, 3, 4]] [0, 1, [2, 3]] {"a": {"b": [0, 1]}} {"a": {"b": [0]}}
清楚了賦值(引用)、copy 還是 deepcopy 之間的區(qū)別才能更好地避免意想不到的錯(cuò)誤,同樣也可以利用它們的特性去實(shí)現(xiàn)一些 little tricks,例如我們?cè)?0x04 閉包與作用域 中利用可變對(duì)象的特性實(shí)現(xiàn) nonlocal 的功能。關(guān)于可變對(duì)象的引用、傳遞等既是 Python 的基本屬性,同時(shí)又因?yàn)殡[藏在背后的“暗箱操作”而容易引起誤解,想要深入了解可以進(jìn)一步閱讀參考鏈接的文章,我也會(huì)在后面的文章中繼續(xù)一邊學(xué)習(xí)、一邊補(bǔ)充更多這方面的知識(shí)。
歡迎關(guān)注公眾號(hào) PyHub!
參考python基礎(chǔ)(5):深入理解 python 中的賦值、引用、拷貝、作用域
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/37822.html
摘要:項(xiàng)目地址所有用過的人應(yīng)該都看過下面兩行錯(cuò)誤信息這就是界的錕斤拷今天和接下來幾期的內(nèi)容將主要關(guān)注中的字符串字節(jié)及兩者之間的相互轉(zhuǎn)換。 項(xiàng)目地址:https://git.io/pytips 所有用過 Python (2&3)的人應(yīng)該都看過下面兩行錯(cuò)誤信息: UnicodeEncodeError: ascii codec cant encode characters in position...
摘要:可以通過一個(gè)簡單的例子來展示當(dāng)然,也可以用狀態(tài)變量的做法來替代總結(jié)有人覺得的這些用法違反直覺或者是而非,不值得提倡。 項(xiàng)目地址:https://git.io/pytips 我們都知道 Python 中 else 的基本用法是在條件控制語句中的 if...elif...else...,但是 else 還有兩個(gè)其它的用途,一是用于循環(huán)的結(jié)尾,另一個(gè)是用在錯(cuò)誤處理的 try 中。這原本是 P...
摘要:項(xiàng)目地址作為一種腳本語言,可以非常方便地用于系統(tǒng)尤其是系統(tǒng)命令行工具的開發(fā)。自身也集成了一些標(biāo)準(zhǔn)庫,專門用于處理命令行相關(guān)的問題。命令行工具的一般結(jié)構(gòu)標(biāo)準(zhǔn)輸入輸出系統(tǒng)中,一切皆為文件,因此標(biāo)準(zhǔn)輸入輸出可以完全可以看做是對(duì)文件的操作。 項(xiàng)目地址:https://git.io/pytips Python 作為一種腳本語言,可以非常方便地用于系統(tǒng)(尤其是*nix系統(tǒng))命令行工具的開發(fā)。Pyt...
摘要:項(xiàng)目地址提供兩種內(nèi)置排序方法,一個(gè)是只針對(duì)的原地排序方法,另一個(gè)是針對(duì)所有可迭代對(duì)象的非原地排序方法。 項(xiàng)目地址:https://git.io/pytips Python 提供兩種內(nèi)置排序方法,一個(gè)是只針對(duì) List 的原地(in-place)排序方法 list.sort(),另一個(gè)是針對(duì)所有可迭代對(duì)象的非原地排序方法 sorted()。 所謂原地排序是指會(huì)立即改變被排序的列表對(duì)象,就...
摘要:項(xiàng)目地址列表推導(dǎo)中提到的方法可以通過簡化的語法快速構(gòu)建我們需要的列表或其它可迭代對(duì)象,與它們功能相似的,還提供列表推導(dǎo)的語法。 項(xiàng)目地址:https://git.io/pytips 0x03 - Python 列表推導(dǎo) 0x02 中提到的 map/filter 方法可以通過簡化的語法快速構(gòu)建我們需要的列表(或其它可迭代對(duì)象),與它們功能相似的,Python 還提供列表推導(dǎo)(List C...
閱讀 2394·2023-04-26 02:54
閱讀 2317·2021-10-14 09:43
閱讀 3366·2021-09-22 15:19
閱讀 2846·2019-08-30 15:44
閱讀 2704·2019-08-30 12:54
閱讀 988·2019-08-29 18:43
閱讀 1939·2019-08-29 17:12
閱讀 1333·2019-08-29 16:40