Python值傳遞還是引用傳遞

2021-08-25 05:41:46 字數 2418 閱讀 5935

python作為一門動態語言,變數本身的型別是不固定的,因此更加靈活。那python到底是值傳遞還是引用傳遞呢?

本人在本週寫**時,遇到這麼乙個讓我注意的問題,問題可以抽象如下:

def func(val1):

val2 = val1

...a =

...(一系列對a的操作)

b = a

func(a)

print(b)

當我執行上述後,發現「b」的值也發生了改變。由此引發了我對python傳值方式的注意。

首先需要明確的是,python中一切事物皆物件,變數是對物件在記憶體中的儲存和位址的抽象。 

a = "abc"
python直譯器其實順序幹了兩件事情: 

1、在記憶體中建立乙個字串「abc」; 

2、在記憶體中建立乙個名為「a」的變數,並將「a」指向字串「abc」(將「abc」的位址儲存到「a」中)。 

這樣我們就能通過操作「a」而改變記憶體中的「abc」。 

所以執行下面語句

a = "123"

b = a

a = "xyz"

執行第一句python直譯器建立字串「123」和變數「a」,並把「a」指向「123」。 

執行第二句,因為「a」已經存在,並不會建立新的物件,但會建立變數「b」,並把「b」指向「a」指向的字串「123「。 

執行第三句,首先會建立字串「xyz」,然後把「xyz」的位址賦予「a「(「a」指向字串「xyz」)。 

我們可以通過呼叫id()方法檢視變數所指向物件在記憶體中的位址。

a = "123"

id(a) # 2248238011648,這個數字就代表了a所指向的物件在記憶體中位址

python引數傳遞統一使用的是引用傳遞方式。因為python物件分為可變物件(list,dict,set等)和不可變物件(number,string,tuple等),當傳遞的引數是可變物件的引用時,因為可變物件的值可以修改,因此可以通過修改引數值而修改原物件,這類似於c語言中的引用傳遞;當傳遞的引數是不可變物件的引用時,雖然傳遞的是引用,引數變數和原變數都指向同一記憶體位址,但是不可變物件無法修改,所以引數的重新賦值不會影響原物件,這類似於c語言中的值傳遞。 

所以回到上面的問題引出,變數「a」,「b」,「val1」,「val2」其實都指向同一可變物件的記憶體位址,當通過變數「val2」對物件進行修改時,其他變數的值也相應被修改了。

既然python只允許引用傳遞,那有沒有辦法可以讓兩個變數不再指向同一記憶體位址呢? 

python提供了乙個copy模組,幫助我們完成這件事。 

1、不使用copy模組 

可以發現變數「a」,「b」指向同一塊記憶體區域,所以對其中乙個的操作將會影響到另乙個。 

2、使用copy模組 

變數「e」和「f」是通過copy方式建立的,可以看見他們的idhubu相同,並且與「c」不同,說明採用copy方式會將物件拷貝乙份到新的記憶體位址中。但copy和deepcopy有什麼區別呢?接著往下實驗 

從紅色框出來處可以看見,雖然使用copy()方法,變數「i」指向的記憶體和「g」不再相同,但是「i」和「g」第二層列表還是同乙個位址。但是deepcopy()方法第二層列表的位址也和「g」不同了。 

所以我們說,copy()是淺拷貝,不管物件多麼複雜,都只拷貝第一層。 

deepcopy()是深拷貝,完全複製原變數的所有層的所有資料,在記憶體中生成一套完全相同的內容。 

python函式是值傳遞還是引用傳遞

在網上看python的基礎知識,看到函式這一章的時候,看到這麼一段話 所有引數 自變數 在python裡都是按引用傳遞。如果你在函式裡修改了引數,那麼在呼叫這個函式的函式裡,原始的引數也被改變了。def changeme mylist 修改傳入的列表 print 函式內取值 mylist retur...

Java是值傳遞還是引用傳遞?

廢話不多說,上 很簡單,圖一中呼叫靜態方法intvalues int t 毫無疑問是傳遞值,因為如果是引用傳遞,那麼二者列印的值是一致的。很明顯,a 之後,t的值沒有發生改變。圖二也是一樣,清晰明了,把方法引數的值賦值給a,然後改變a的值,二者值列印均一致,那是因為t代表的是乙個堆記憶體的位址,基本...

Java是值傳遞還是引用傳遞

基本型別 如上圖所示,基本型別傳遞時,執行緒在棧上分配形式引數並拷貝實際引數的值。create with intellij idea author wangzhenpeng date 2018 4 8 time 上午9 48 e mail wangzhenpeng0924 163.com descr...