1. 程式人生 > >關於copy與deepcopy引發的思考學習

關於copy與deepcopy引發的思考學習

#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))