參數的傳遞
函數的參數傳遞本質上就是:從實參到形參的賦值操作。Python中“一切皆對象”,所有的賦值操作皆是“引用賦值”,所以,Python中參數的傳遞都是“引用傳遞”,不是“值傳遞”,具體操作可分爲兩類:
- 對“可變對象”進行“寫操作”,直接作用於原對象本身。
- 對“不可變對象”進行“寫操作”,會產生一個新的“對象空間”,並用新的值填充這塊空間(起到其他語言的“值傳遞”效果,但不是“值傳遞”)。
可變對象有:
字典、列表、集合、自定義的對象等
不可變對象有:
數字、字符串、元組、function等
傳遞可變對象的引用
傳遞參數是可變對象(如:字典、列表、自定義的其他可變對象等),實際傳遞的還是對象的引用。在函數體中不創建新的對象拷貝,而是可以直接修改所傳遞的對象。
例子:
b=[10,20]
def one(n):
print("n",id(n)) #b和n是同一個對象,n是局部變量
n.append(55) #由於n是可變對象,不創建對象拷貝,直接修改這個對象
one(b)
print("b",id(b))
print(b)
執行返回:
>>>n 1542470710600
b 1542470710600
[10, 20, 55]
注意(個人理解)(圖裏缺局部棧幀那一塊)點擊此處:
- 上面函數的內存分析。棧爲變量,堆爲內存。變量b指向內存對象(內存地址爲id(b)也就是打印出來1542470710600),內存對象有包含兩個對象(10和20)有可以理解內存對象的索引1和2分別指向10和20。最終指向b。
- 調用函數的把對象b傳遞給n,因爲n是局部變量,將形成棧幀,棧幀引用指向b的內存對象,所以n加55,在b的內存對象裏面也是增加一個對象指向30的對象,同時對象30地址給了內存對象裏面。棧幀消失,結果不變
傳遞不可變對象的引用
傳遞參數是不可變對象(例如:int、float、字符串、元組、布爾值等),實際傳遞的還是對象的引用,早“賦值操作”時,由於不可變對象無法修改,系統會創建一個新的對象。
操作:參數傳遞,傳遞不可變對象的引用
a=100
def one(n):
print("n",id(n)) #傳遞進來的是a對象地址
n=n+100 #由於a是不可變對象,因此創建新的對象n
print("n1",id(n)) #n已經變成新的對象
print(n)
one(a)
print("A",id(a))
返回值:
>>>n 1655292064
n1 1655295264
200
A 1655292064
顯然,通過id值可以看到n和a一開始是一個對象,給n賦值後,n是新的對象。
參數傳遞,不可變對象含可變對象
傳遞不可變對象時用的是淺拷貝,點擊查看淺拷貝和深拷貝的區別
傳遞參數是不可變對象(例如:int,float,字符串、元組、布爾值),實際傳遞的還是對象的引用。但在“寫操作”時,會創建一個新的對象拷貝。這個拷貝使用的是“淺拷貝”,不是深拷貝。
a=(10,20,[2,3]) #元組是不可變對象,列表是可變對象
print("a:",id(a))
def test_1(b):
print('b:',id(b))
b[2][0]=666
print(b)
print('b_:',id(b))
test_1(a)
print(a)
返回:
>>>a: 2128142246680
b: 2128142246680
(10, 20, [666, 3])
b_: 2128142246680
(10, 20, [666, 3])
注:傳遞不可變對象時,不可變對象裏面包含的子對象是可變的,則方法內修改這個可變對象,源對象已發生了變化。