Python 中變數賦值傳遞時的引用和複製介紹
導讀 | Python 賦值過程中不明確區分複製和引用,一般對靜態變數的傳遞為複製,對動態變數的傳遞為引用。 |
曾經看到這樣一個問題,一個字典中的元素是列表,將這個列表元素賦值給一個變數,然後修改這個列表中元素的值,結果發現,字典中那個列表也同樣修改了。那個問題如下:
dict = {'a':[1,2,3,4,5],'b':2} x = dict['a'] for i in range(5): x[i] = 0 print(dict['a'])
程式執行結果如下:
[0, 0, 0, 0, 0]
這兒涉及到Python賦值到底是引用還是複製一份的問題,即賦值時是傳值還是傳址。上面問題是將"a"的值賦給了x出現了上述情況,如果是將"b"的值賦給了x,當我們修改x的值時,字典dict的值並不受影響。
>>> dict = {'a':[1,2,3,4,5],'b':2} >>> x = dict['b'] >>> x 2 >>> x=x+3 >>> x 5 >>> dict {'a': [1, 2, 3, 4, 5], 'b': 2} >>>
那麼問題來了,變數賦值傳遞時什麼情況下是傳值(複製),什麼情況下是傳址(引用)呢?
當我們不知道是引用還是複製的情況下,可以顯式的複製。比如字典物件本身都具有複製的方法:
x=dict.copy()
沒有複製方法的物件,也是可以複製的。這兒我們引入一個深複製的概念,深複製——即python的copy模組提供的一個deepcopy方法。深複製會完全複製原變數相關的所有資料,在記憶體中生成一套完全一樣的內容,在這個過程中我們對這兩個變數中的一個進行任意修改都不會影響其他變數。還是上面的程式碼,如果改成如下:
import copy dict = {'a':[1,2,3,4,5],'b':2} x = copy.deepcopy(dict['a']) for i in range(5): x[i] = 0 print(dict['a'])
執行結果dict值不受影響。
除了深複製,copy模組還提供一個copy方法,稱其為淺複製,對於簡單的物件,深淺複製都是一樣的,上面的詞典物件的copy方法就是淺複製。
>>> dict {'a': [8, 2, 3, 4, 5], 'b': 4} >>> dd=copy.copy(dict) >>> dd {'a': [8, 2, 3, 4, 5], 'b': 4} >>> dd['a'][0]=7 >>> dd {'a': [7, 2, 3, 4, 5], 'b': 4} >>> dict {'a': [7, 2, 3, 4, 5], 'b': 4} >>> ee=dict.copy() >>> ee {'a': [7, 2, 3, 4, 5], 'b': 4} >>> ee['a'][0]=9 >>> ee {'a': [9, 2, 3, 4, 5], 'b': 4} >>> dict {'a': [9, 2, 3, 4, 5], 'b': 4} >>> ee['b']=5 >>> ee {'a': [9, 2, 3, 4, 5], 'b': 5} >>> dict {'a': [9, 2, 3, 4, 5], 'b': 4} >>>
淺複製時改變第一層次相互不受影響(上例中詞典b值的修改),第二層次(上例中詞典a的列表值修改)就相互影響了,改一個,其他跟著變。看看id吧:
>>> id(dict) 20109472 >>> id(dd) 20244496 >>> id(ee) 20495072 >>> id(dd['a']) 20272112 >>> id(ee['a']) 20272112 >>> id(dict['a']) 20272112 >>>
可見詞典各個複製的id是不同的,但詞典a值的id是相同的。如果我們需要真正意義的複製,就用深複製吧。
Python 賦值過程中不明確區分複製和引用,一般對靜態變數的傳遞為複製,對動態變數的傳遞為引用。(注,對靜態變數首次傳遞時也是引用,當需要修改靜態變數時,因為靜態變數不能改變,所以需要生成一個新的空間儲存資料)。
- 字串,數值,元組均為靜態變數
- 列表,字典為動態變數
變數有時比較複雜,存在組合現象,比如字典中包含列表,列表中包含字典,但賦值時,總是屬於某個型別。如果實在不清楚狀況,可以試驗一下,用id()這個函式看看,如果是引用,兩個變數指向的地址是相同的。例如:
>>> a=6 >>> id(a) 10413476 >>> b=a >>> id(b) 10413476 >>> b=8 >>> id(b) 10413452 >>>
修改變數b之前,a和b指向的地址是相同的,修改b後,地址就變了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2767443/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 值傳遞和引用傳遞
- Python的函式引數傳遞:傳值?引用?Python函式
- JavaScript的值傳遞和引用傳遞JavaScript
- Java的值傳遞和引用傳遞Java
- python的賦值傳遞Python賦值
- 簡單介紹Lua中的變數與賦值方法變數賦值
- Day30--值傳遞和引用傳遞
- php之普通變數賦值、物件賦值、引用賦值的區別PHP變數賦值物件
- 關於值傳遞和引用傳遞的解釋
- Python引數傳遞,既不是傳值也不是傳引用Python
- 面試官問:Go 中的引數傳遞是值傳遞還是引用傳遞?面試Go
- C#程式設計引用型別和值型別 以及引用傳遞和值傳遞C#程式設計型別
- python中的引用傳遞,可變物件,不可變物件,list注意點Python物件
- Java 從陣列來看值傳遞和引用傳遞Java陣列
- 快速搞懂值傳遞與引用傳遞
- Python中的賦值與淺複製與深複製之間的關係Python賦值
- MySQL中變數的定義和變數的賦值使用MySql變數賦值
- PHP 物件導向 (四)類物件賦值為引用傳遞PHP物件賦值
- Java - 是值傳遞還是引用傳遞Java
- 淺複製和深複製的概念與值複製和指標複製(引用複製)有關 淺複製 “指標複製 深複製 值複製指標
- 複製和引用複製
- 複製物件重新賦值不改變原物件物件賦值
- 這一次,徹底解決Java的值傳遞和引用傳遞Java
- Go語言引數傳遞是傳值?還是傳引用 ?Go
- 這一次,讓你徹底理解Java的值傳遞和引用傳遞!Java
- FastReport VCL在 TfrxReport.OnGetValue 中傳遞變數值AST變數
- golang工作筆記(二)值傳遞與引用傳遞Golang筆記
- 解惑4:java是值傳遞還是引用傳遞Java
- 常被新手忽略的值賦值和引用賦值(偏redux向)賦值Redux
- vue 變數賦值同時改變的問題Vue變數賦值
- [精]--這一次,讓你徹底明白Java的值傳遞和引用傳遞!Java
- 可能是最淺顯易懂的一篇文章,關於Python引用、賦值、複製Python賦值
- ABAP 方法呼叫的引數傳遞裡,透過引用傳遞的方式,能修改原始引數值嗎?
- PHP中物件的引用傳遞PHP物件
- C#|.net core 基礎 - 值傳遞 vs 引用傳遞C#
- go語言引數傳遞到底是傳值還是傳引用Go
- chan中傳遞map資料,傳遞的是引用
- 變數的賦值 指標間接賦值變數賦值指標