在 python 中定義函式時,可以為其指定預設引數
,這樣就不必在每次呼叫函式時都傳遞引數進去,並且可以簡化我們的**。
在定義函式時,如果使用了可變型別
來作為函式的預設引數
,往往會產生一些***。來看下面一段**。
def
foo(li=
):1)
print
(li)
foo(
)foo(
)foo(
)
你可能想得到如下的結果:
[1]
[1][1]
但實際上,結果卻是:
[1]
[1, 1]
[1, 1, 1]
根據結果來看,似乎每次的函式呼叫,li
列表都記錄了上一次的呼叫結果,而並沒有使用預設引數
。但是當我們在每次呼叫函式時,都傳遞乙個空列表
進去,就不會出現***,能夠正確得到我們想要的結果。
def
foo(li=
):1)
print
(li)
foo(
)foo(
)foo(
)
[1]
[1][1]
為什麼會產生這樣的結果呢?其實這個問題的原因是 python 中函式的特性所決定的。由於函式也是物件
,而物件
可以有自己的屬性,所以函式也有自己的屬性。
當foo
函式被建立時,它的預設引數
就已經被儲存在它的__defaults__
屬性中了。而函式只會被建立一次,以後每次執行foo()
的時候,都只會呼叫函式,並不會去重新建立乙個函式。所以函式的預設引數
也只會計算一次,無論之後被呼叫多少次,預設引數
始終都是同乙個物件
。
我們用id()
函式列印出缺省引數的記憶體位址就能夠看出來。
def
foo(li=
):1)
print
(li,
id(li)
)foo(
)foo(
)foo(
)
[1] 48904632
[1, 1] 48904632
[1, 1, 1] 48904632
可以看出,三次呼叫函式後,其內部列印的li
位址是相同的,所以它們其實是同乙個物件
。
知道了問題的原因,那麼如果解決它呢?我們可以用none
來作為函式的預設引數
,在呼叫foo
函式時,在函式體內部可以通過判斷li
是否為none
來決定是否需要使用預設值
。這樣,當呼叫foo()
函式並且沒有傳遞引數時,再給li
賦乙個預設值
即可。
def
foo(li=
none):
if li is
none
: li =
1)print
(li)
foo(
)foo(
)foo(
)
[1]
[1][1]
這樣既不用擔心可變型別
作為函式預設引數
時的***,也不用在每次呼叫foo
函式時都傳遞乙個引數進去,能夠很好的解決這個問題。
所以,當我們給函式定義預設引數
時,應該盡量使用不可變型別
以免產生意想不到的***。當然,除非你明確知道你需要用可變型別
的特性來達到某些目的。
Python函式之可變型別與不可變型別
在python語言中,string,tuple,number為不可變型別,但是dict,list為可變型別。所謂的不可變型別就是,a 5實際上指的是吧值為5的記憶體指向a,如果在執行a 10相當於又宣告了乙個值為10的記憶體指向a。例如 結果 兩次列印的a的記憶體位址是不同的。但是對於list的可變...
可變資料型別不能作為python函式的引數
可變資料型別 列表 字典 不可變資料型別 整型 浮點型 字串 元組 為什麼可變資料型別不能作為python函式的引數?請看以下例子 def foo a return aprint foo print foo print foo 結果 1 1,1 1,1,1 print id foo print id...
python的函式(三) 可變型別與不可變型別
python 中有下面幾種不可變型別 不可變型別 就是無法修改的型別,我們無法在記憶體中直接修改這個變數 如 100,student 如果我們嘗試對不可變型別進行修改,就會斷開原始的引用,重新分配記憶體位址。除了不可變型別,其餘的都是可變型別,如 可變型別 就是可以進行修改的型別,修改可變型別的值不...