Python函數參數的傳遞可變對象及不可變對象

參數的傳遞

函數的參數傳遞本質上就是:從實參到形參的賦值操作。Python中“一切皆對象”,所有的賦值操作皆是“引用賦值”,所以,Python中參數的傳遞都是“引用傳遞”,不是“值傳遞”,具體操作可分爲兩類:

  1. 對“可變對象”進行“寫操作”,直接作用於原對象本身。
  2. 對“不可變對象”進行“寫操作”,會產生一個新的“對象空間”,並用新的值填充這塊空間(起到其他語言的“值傳遞”效果,但不是“值傳遞”)。

可變對象有:

       字典、列表、集合、自定義的對象等

不可變對象有:

       數字、字符串、元組、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])

注:傳遞不可變對象時,不可變對象裏面包含的子對象是可變的,則方法內修改這個可變對象,源對象已發生了變化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章