Python的傳值和傳址與copy和deepcopy


1.傳值和傳址

傳值就是傳入一個參數的值,傳址就是傳入一個參數的地址,也就是內存的地址(相當於指針)。他們的區別是如果函數里面對傳入的參數重新賦值,函數外的全局變量是否相應改變,用傳值傳入的參數是不會改變的,用傳址傳入就會。

a=1
def f(b):
    b=2
f(a)
print a

例如這段代碼里面,首先聲明a的值為1,把a作為參數傳入到函數f里面,函數f里面對b重新賦值為2,如果是傳值的形式傳入a的話,a的值是不會變的,依然為1,如果以傳址的形式傳入a,a就會變成2。這個就是傳值和傳址的區別。

而在python中的傳址和傳值是怎樣的呢?

Python是不允許程序員選擇采用傳值還是傳址的。Python參數傳遞采用的肯定是“傳對象引用”的方式。實際上,這種方式相當於傳值和傳址的一種綜合。如果函數收到的是一個可變對象(比如字典或者列表)的引用,就能修改對象的原始值——相當於傳址。如果函數收到的是一個不可變對象(比如數字、字符或者元組)的引用,就不能直接修改原始對象——相當於傳值。

所以python的傳值和傳址是根據傳入參數的類型來選擇的

傳值的參數類型:數字,字符串,元組

傳址的參數類型:列表,字典

a=1
def f(a):
    a+=1
f(a)
print a

這段代碼里面,因為a是數字類型,所以是傳值的方式,a的值並不會變,輸出為1

a=[1]
def f(a):
    a[0]+=1
f(a)
print a

這段代碼里面,因為a的類型是列表,所以是傳址的形式,a[0]的值會改變,輸出為[2]

2.copy和deepcopy

不止是函數里面,函數外面的引用也同樣遵循這個規則:

a=1
b=a
a=2
print a,b
a=[1]
b=a
a[0]=2
print a,b

第一個輸出為2,1,第二個輸出為 [2] [2]

b=a

所以在python中,當運行上面的代碼時,如果a是字典或者列表的話,程序執行的操作並不是新建一個b變量,然后a的值復制給b,而是新建一個b變量,把b的值指向a,也就是相當於在c語言里面的新建一個指向a的指針。
所以當a的值發生改變時,b的值會相應改變。

但是,當我們想新建一個與a的值相等的b變量,同時b的值與a的值沒有關聯時,要怎么做?這時就用到copy與deepcopy了

import copy

a=[1,2,3]
b=a
a.append(4)
print a,b

a=[1,2,3]
b=copy.copy(a)
a.append(4)
print a,b

上面的輸出為:

[1, 2, 3, 4] [1, 2, 3, 4]
[1, 2, 3, 4] [1, 2, 3]

這里用了copy來讓b與a相等,后面如果修改了a的值,b的值並不會改變。看來copy已經可以實現我們上面的提到的需求了,那么deepcopy又有什么用?

如果我們遇到這種情況,copy就解決不了了

a=[1,[1,2],3]
b=copy.copy(a)
a[1].append(4)
print a,b

這里輸出的結果為:[1, [1, 2, 4], 3] [1, [1, 2, 4], 3]  ,這樣的結果明顯不是我們想要的

當列表或字典參數里面的值是列表或字典時,copy並不會復制參數里面的列表或字典,這時就要用到deepcopy了

a=[1,[1,2],3]
b=copy.deepcopy(a)
a[1].append(4)
print a,b

輸出的結果為:[1, [1, 2, 4], 3] [1, [1, 2], 3]

 

 參考資料:http://luchanghong.com/python/2012/09/21/the-differences-between-copy-and-deepcopy-in-python.html

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM