深入淺析Python傳值與傳址
1. 傳值與傳址的區(qū)別
傳值就是傳入一個參數(shù)的值,傳址就是傳入一個參數(shù)的地址,也就是內(nèi)存的地址(相當于指針)。他們的區(qū)別是如果函數(shù)里面對傳入的參數(shù)重新賦值,函數(shù)外的全局變量是否相應(yīng)改變:用傳值傳入的參數(shù)是不會改變的,用傳址傳入就會。
def a(n): n[2] = 100 print(n) return None def b(n): n += 100 print(n) return None an = [1,2,3,4,5] bn = 10 print(an) a(an) print(an) print(bn) b(bn) print(bn) [1, 2, 3, 4, 5] [1, 2, 100, 4, 5] [1, 2, 100, 4, 5] 10 110 10
在上面的例子中,an是一個list,將其作為實參傳入函數(shù)a中,a對其第三個元素進行修改。a執(zhí)行結(jié)束后再次打印an,發(fā)現(xiàn)里面的元素的確發(fā)生變化,這就是傳址操作。bn代表一個數(shù)字,將其傳入函數(shù)b,并做修改,b執(zhí)行結(jié)束后再次打印bn,沒有變化,這是傳值操作。
2. Python中傳值與傳址的規(guī)律
Python是不允許程序員選擇采用傳值還是傳址的。Python參數(shù)傳遞采用的是“傳對象引用”的方式,實際上,這種方式相當于傳值和傳址的一種綜合。
如果函數(shù)收到的是一個可變對象(比如字典或者列表)的引用,就能修改對象的原始值——相當于傳址。如果函數(shù)收到的是一個不可變對象(比如數(shù)字、字符或者元組)的引用,就不能直接修改原始對象——相當于傳值。所以python的傳值和傳址是根據(jù)傳入?yún)?shù)的類型來選擇的。
傳值的參數(shù)類型:數(shù)字,字符串,元組
傳址的參數(shù)類型:列表,字典
3. 內(nèi)置函數(shù)id
內(nèi)置函數(shù)id,負責顯示一個變量或者數(shù)據(jù)在內(nèi)存中的地址,有時可以用來檢測所使用的對象是否為同一個,幫助區(qū)別傳值與傳址操作。
但是id在有些情況下比較特殊,注意下面的例子。
a = 100 b = 200 print(id(a)) print(id(b)) c = a print(id(c)) print(a is c) a += 300 print(a) print(c) print(a is c) print(id(a)) print(id(c)) 1549495552 1549498752 1549495552 True 400 100 False 93638128 1549495552
為了提高內(nèi)存利用效率,對于一些簡單的對象,如一些數(shù)值較小的int對象,python采取重用對象內(nèi)存的辦法。如指向a=100,c=100時,由于100作為簡單的int類型且數(shù)值小,python不會兩次為其分配內(nèi)存,而是只分配一次,然后將a與c同時指向已分配的對象。但是當a的值發(fā)生變化時,會單獨為a重新分配一個新的內(nèi)存。
4. list傳值與傳址
list類型使用簡單的賦值操作,是傳址。
a = [1,2,3,4,5] b = a print(a) b[2] = 333 print(a) print(b) print(id(a)) print(id(b)) [1, 2, 3, 4, 5] [1, 2, 333, 4, 5] [1, 2, 333, 4, 5] 96142472 96142472
copy函數(shù)是淺拷貝,是傳值。python2中,需要import copy模塊,python3可直接使用。
a = [1,2,3,4,5] b = a.copy() print(a) b[2] = 333 print(a) print(b) print(id(a)) print(id(b)) [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] [1, 2, 333, 4, 5] 92990536 96202632
由于copy是淺拷貝,只拷貝一層的內(nèi)容,當遇到下列情況時,copy不能實現(xiàn)完全的傳值操作。
a = [1,2,3,[10,20,30]] b = a.copy() print(id(a)) print(id(b)) print(id(a[3])) print(id(b[3])) a[3][2] = 666 print(a) print(b) 96141704 93355400 96141768 96141768 [1, 2, 3, [10, 20, 666]] [1, 2, 3, [10, 20, 666]]
要解決這個問題,需要使用deepcopy。python3中,直接可以使用copy()方法,但deepcopy()還是需要導入copy模塊。
import copy a = [1,2,3,[10,20,30]] b = copy.deepcopy(a) print(id(a)) print(id(b)) print(id(a[3])) print(id(b[3])) a[3][2] = 666 print(a) print(b) 96503944 93002376 96886024 93352712 [1, 2, 3, [10, 20, 666]] [1, 2, 3, [10, 20, 30]]
5. tuple操作
tuple元組是不可修改的,指的是其元組內(nèi)容不可改。
t1 = (1,2,3) t1[1] = 100 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-19-9caf76a526a9> in <module>() 1 t1 = (1,2,3) ----> 2 t1[1] = 100 TypeError: 'tuple' object does not support item assignment
但是其所指向的內(nèi)存地址是可變的。
t1 = (1,2,3) t2 = (5,6,7) print(id(t1)) t1 += t2 print(t1) print(id(t1)) print(id(t2)) t2 *= 3 print(t2) print(id(t2)) 96151520 (1, 2, 3, 5, 6, 7) 93048552 94080672 (5, 6, 7, 5, 6, 7, 5, 6, 7) 93656912
并不是起初的t1和t2所指向的元組內(nèi)容發(fā)生了變化,而是新分配了兩個元組內(nèi)存,t1和t2所指向的內(nèi)存發(fā)生改變。
總結(jié)
相關(guān)文章
Python?Pandas教程之series 上的轉(zhuǎn)換操作
這篇文章主要介紹了Python?Pandas教程之series上的轉(zhuǎn)換操作,文章通過圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09