面試的時候,有沒有被問到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 過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在堆疊中開闢了記憶體...