關於copy與deepcopy引發的思考學習
阿新 • • 發佈:2018-12-25
#1. 傳值與傳址的區別
# 傳值就是傳入一個引數的值,傳址就是傳入一個引數的地址,也就是記憶體的地址(相當於指標)。
#他們的區別是如果函式裡面對傳入的引數重新賦值,函式外的全域性變數是否相應改變:用傳值傳入的引數是不會改變的,用傳址傳入就會。
1 ''' 2 an是一個list,將其作為實參傳入函式a中,a對其第三個元素進行修改。a執行結束後再次列印an,發現裡面的元素的確發生變化,這就是傳址操作。 3 4 ''' 5 def a(n): 6 n[2] = 100 7 print(n) 8 return None 9 ''' 10 bn代表一個數字,將其傳入函式b,並做修改,b執行結束後再次列印bn,沒有變化,這是傳值操作。11 ''' 12 def b(n): 13 n += 100 14 print(n) 15 return None 16 17 an = [1,2,3,4,5] 18 bn = 10 19 20 print(an) 21 print(id(an)) 22 a(an) 23 print(an) 24 print(id(an)) 25 print(bn) 26 print(id(bn)) 27 b(bn) 28 print(bn) 29 print(id(bn))
# Python中傳值與傳址的規律
# Python是不允許程式設計師選擇採用傳值還是傳址的。Python引數傳遞採用的是“傳物件引用”的方式,實際上,這種方式相當於傳值和傳址的一種綜合。
# 如果函式收到的是一個可變物件(比如字典或者列表)的引用,就能修改物件的原始值——相當於傳址。如果函式收到的是一個不可變物件(比如數字、字元或者元組)的引用,就不能直接修改原始物件——相當於傳值。
# 所以python的傳值和傳址是根據傳入引數的型別來選擇的。
# 傳值的引數型別:數字,字串,元組
# 傳址的引數型別:列表,字典
# tuple元組是不可修改的,指的是其元組內容不可改。但是其所指向的記憶體地址是可變的。 t1 = (1,2,3) t2 = (5,6,7) print(t1) print(id(t1)) print(t2) print(id(t2)) t1 += t2 print(t1) print(id(t1)) print(id(t2)) t2 *= 3 print(t2) print(id(t2))
#為了提高記憶體利用效率,對於一些簡單的物件,如一些數值較小的int物件,python採取重用物件記憶體的辦法。
# 如指向a=100,c=100時,由於100作為簡單的int型別且數值小,python不會兩次為其分配記憶體,而是隻分配一次,然後將a與c同時指向已分配的物件。
# 但是當a的值發生變化時,會單獨為a重新分配一個新的記憶體。
# 當把a的值賦值給C時為了節省記憶體只是在記憶體指向上同時把這一片記憶體指向了a和c。 a = 100 print(id(a)) c = a print(id(c)) print(a is c) # 當a的值發生變化的時候則才會重新分配一片記憶體指向給a a += 300 print(a) print(c) print(a is c) print(id(a)) print(id(c))
# 列表的切片也是相當於是一種傳址的操作
# 列表的切片也是相當於是一種傳址的操作 a = [1,2,3,4,5,6,7,8,9] b = a[:] c = a[0:4:2] print(a) print(b) print(c) print(id(a)) print(id(b)) print(id(c)) print("此處是分割線 " * 5) # 類似這種的操作叫做傳址或者是傳引用的方式,這種操作方式當進行賦值操作的時候id並未改變只是把地址內的值進行了更改 l = [1,2,3,4,5,6,7,8,9] print(l) l[2] = 100 print(id(l)) print(l) print(id(l))