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

2021-08-19 07:54:44 字數 2599 閱讀 6314

面試的時候,有沒有被問到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))# 2587116690248b =

1print(id

(b))# 2006430784

b +=

1print(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 +=

1print(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

orb +=[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 過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在堆疊中開闢了記憶體...