Python引數傳遞,既不是傳值也不是傳引用

2021-09-11 17:29:20 字數 2354 閱讀 8600

面試的時候,有沒有被問到python傳參是傳引用還是傳值這種問題?有沒有聽到過python傳參既不是傳值也不是傳引用這種說法?乙個小小的引數預設值也可能讓**出現難以查詢的bug?

如果你也遇到過上面的問題,不妨我們來**下python函式傳遞的種種。

python中有乙個非常重要的概念——萬物皆物件,無論是乙個數字、字串,還是陣列、字典,在python中都會以乙個物件的形式存在。

a = 123

複製**

對於上面這行**,在python看來就是建立乙個pyobject物件,值為123,然後定義乙個指標a,a指向這個pyobject物件。

python中的物件分為兩種型別,可變物件和不可變物件,不可變物件指tuple、str、int等型別的物件,可變物件指的是dict、list、自定義物件等型別的物件,我們用一段**說明他們的區別。

a = [1, 2, 3]

print(id(a)) # 2587116690248

a += [4]

print(id(a)) # 2587116690248

b = 1

print(id(b)) # 2006430784

b += 1

print(id(b)) # 2006430816

複製**

上面**中我們分別定義了乙個可變物件和乙個不可變物件,並且對他們進行修改,列印修改前後的物件標識可以發現,對可變物件進行修改,變數對其引用不會發生變化,對不可變物件進行修改,變數引用發生了變化。

上圖是乙個可變物件,當修改物件時,例如刪除陣列中的乙個元素,實際上把其中乙個元素從物件中移除,物件本身的標識是不發生變化的。

改變乙個不可變物件時,例如給乙個int型加2,語法上看上去是直接修改了i這個物件,但是如前面所說,i只是乙個指向物件73的乙個變數,python會將這個變數指向的物件加2後,生成乙個新的物件,然後再讓i指向這個新的物件。

了解了物件的原理後,我們就可以來嘗試理解一下引數傳遞時他們的不同表現了。

a = [1, 2, 3]

print(id(a)) # 1437494204232

defmutable

(a):

print(id(a)) # 1437494204232

a += [4]

print(id(a)) # 1437494204232

mutable(a)

b = 1

print(id(b)) # 2006430784

defimmutable

(b):

print(id(b)) # 2006430784

b += 1

print(id(b)) # 2006430816

immutable(b)

複製**

通過上面的**可以看出,修改傳進的可變引數時,會對外部物件產生影響,修改不可變引數時則不會影響。

概括地說,python引數傳遞時,既不是傳物件也不是傳引用,之所以會有上述的區別,跟python的物件機制有關,引數傳遞只是給物件繫結了乙個新的變數(實際上是傳遞c中的指標)。

理解了引數傳遞的邏輯,我們需要注意一下這種邏輯可能引發的問題。

def

test

(b=):

b += [1]

print(b)

test() # [1]

test() # [1, 1]

test() # [1, 1, 1]

複製**

上面的**的輸出,按照可變物件傳參的邏輯,應該每次呼叫都輸出[1]才對,而實際輸出看上去好像預設引數好像只生效了一次。原因在於python的函式也是物件(萬物皆物件),這個物件只初始化一次,加上引數又是不可變物件,所以每次呼叫實際上都修改的是乙個物件。

解決這個問題,推薦再引數傳遞可變物件時,預設值設定為none,在函式內部對none進行判斷後再賦予預設值。

def

test

(b=none):

b = b or

b += [1]

print(b)

test() # [1]

test() # [1]

test() # [1]

複製**

再看一段**。

i = 1

deftest

(a=i):

print(a)

i = 2

test() # 1

複製**

由於引數預設值是在函式定義時而不是函式執行時確定的,所以這段**test方法的引數預設值時1而不是2。

Python引數傳遞,既不是傳值也不是傳引用

面試的時候,有沒有被問到python傳參是傳引用還是傳值這種問題?有沒有聽到過python傳參既不是傳值也不是傳引用這種說法?乙個小小的引數預設值也可能讓 出現難以查詢的bug?如果你也遇到過上面的問題,不妨我們來 下python函式傳遞的種種。萬物皆物件 python中有乙個非常重要的概念 萬物皆...

python的引數傳遞是值傳遞還是引用傳遞?

函式引數傳遞機制,傳值和引用的是什麼意思?函式引數傳遞機制問題在本質上是呼叫函式 過程 和被呼叫函式 過程 在呼叫發生時進行通訊的方法問題。基本的引數傳遞機制有兩種 值傳遞和引用傳遞。值傳遞 passl by value 過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在堆疊中開闢了記憶體...

python的引數傳遞是值傳遞還是引用傳遞??

函式引數傳遞機制,傳值和引用的是什麼意思?函式引數傳遞機制問題在本質上是呼叫函式 過程 和被呼叫函式 過程 在呼叫發生時進行通訊的方法問題。基本的引數傳遞機制有兩種 值傳遞和引用傳遞。值傳遞 passl by value 過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在堆疊中開闢了記憶體...