可變數據類型不能作為python函數的參數
可變數據類型:列表、字典
不可變數據類型:整型、浮點型、字元串、元組
為什麼可變數據類型不能作為python函數的參數?請看以下例子:
def foo(a=[]): a.append(1) return a print(foo()) print(foo()) print(foo())
結果:
[1] [1, 1] [1, 1, 1]
我們繼續列印下每次函數的返回值的記憶體地址:
print(id(foo())) print(id(foo())) print(id(foo()))
結果:
140344852133960 140344852133960 140344852133960
會發現我們每次返回的都是同一個對象。
再看下以下例子:
b = [1,2] def test(place=b): place.append(1) return place print(b) print(test()) print(b) print(test()) print(b)
結果:
[1, 2] [1, 2, 1] [1, 2, 1] [1, 2, 1, 1] [1, 2, 1, 1]
當使用列表作為參數傳入函數時,實際上是引用傳遞。也就是傳入的是實際參數的地址,而place=b也就是指向相同的地址。比如以下的:
c = [1,2,3] d = c print(id(c)) print(id(d))
結果:
140344851860104 140344851860104
當我們修改d的值時,同樣也會影響到c:
d.append(4) print(d) print(c) print(id(d)) print(id(c))
結果:
[1, 2, 3, 4] [1, 2, 3, 4] 140344851860104 140344851860104
所以在上述中,通過在test()函數中修改place的值也會影響到b的值。
為什麼會這樣呢?
python中一切皆對象。函數也是對象,可以這麼理解,一個函數是一個被它自己定義而執行的對,;默認參數是一種"成員數據",所以它們的狀態和其他對象一樣,會隨著每一次調用而改變。
怎麼避免這種現象呢?
使用以下方式:
def foo(a=None): if a is None: a = [] a.append(1) return a print(foo()) print(foo()) print(foo())
結果:
[1] [1] [1]
如果需要處理任意對象(包括None),則可以使用哨兵對象:
sentinel = object() def myfunc(value=sentinel): if value is sentinel: value = expression # use/modify value here
應用:求數組的全排列
最後我們來看一個應用例子:求數組的全排列
基本思路是回溯法:每次從數組中選一個值加入到tmp中,如果數組中沒有值了,就將tmp加入到結果中,返回。
如果我們的程式碼是這種:
arr = [1,2,3] res = [] def permutation(arr,tmp=[]): global res if len(arr) == 0: res.append(tmp) return for i in range(len(arr)): tmp = tmp + [arr[i]] newArr = arr[:i]+arr[i+1:] permutation(newArr,tmp) subset(arr,tmp=[]) print(res)
結果:
[[1, 2, 3], [1, 2, 3, 2], [1, 2, 1, 3], [1, 2, 1, 3, 1], [1, 2, 3, 1, 2], [1, 2, 3, 1, 2, 1]]
這裡就出現了上述的情況,我們只需要簡單的改以下即可:
arr = [1,2,3] res = [] def permutation(arr,tmp=[]): global res if len(arr) == 0: res.append(tmp) return for i in range(len(arr)): newTmp = tmp + [arr[i]] newArr = arr[:i]+arr[i+1:] permutation(newArr,newTmp) subset(arr,tmp=[]) print(res)
結果:
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
我們只需要每次新建一個列表即可。
參考://blog.csdn.net/rommi/article/details/51979556

