1. 可變的默認參數python
錯誤示例閉包
>>> def lala(l=[]): ... l.append(123) ... print l ... >>> lala() [123] >>> lala() [123, 123] >>> lala() [123, 123, 123]
緣由是,一個函數的默認值,僅在函數被定義時賦值一次。app
解決方法函數
>>> def lala(l=None): ... if l is None: ... l = [] ... l.append(123) ... print l ... >>> lala() [123] >>> lala() [123] >>> lala([456]) [456, 123]
2. 閉包問題spa
問題1:指望獲得一個每執行一次,數字加1的函數code
錯誤示例對象
>>> def counter(): ... count = 0 ... def func(): ... count += 1 ... print count ... return func ... >>> lala = counter() >>> lala() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in func UnboundLocalError: local variable 'count' referenced before assignment
錯誤的緣由是,在python中,當試圖爲一個變量賦值時,會認爲該變量在local(見《命名空間與做用域》)blog
正確的作法作用域
>>> def counter(): ... count = [0] ... def func(): ... count[0] += 1 ... print count[0] ... return func ... >>> lala = counter() >>> lala() 1 >>> lala() 2
由於在list是可變對象,所以能夠巧妙的跳過這個限制。for循環
3. for 循環相關
1. 循環的同時修改列表
目的:傳入一個純數字的列表,將每一個數字的平方添加在原列表中
錯誤的作法:
>>> def lala(l): ... for i in l: ... l.append(i**2) ... >>> lala([1,2,3]) #死循環
正確作法: 用list[:]得到一個拷貝
>>> def lala(l): ... for i in l[:]: ... l.append(i**2) ... return l ... >>> lala([1,2,3]) [1, 2, 3, 1, 4, 9]
2. for循環不會引入新的命名空間
>>> for i in [1,2,3]: ... print i ... 1 2 3 >>> i 3
感受i應該是循環內部使用的一個變量,可是卻發現循環結束後,它"泄漏"到外部了,這個沒有解決辦法,本身注意一下吧
3. for循環閉包問題
目的:指望獲得5個函數,分別是將一個數字與0,1,2,3,4相乘
錯誤作法:
>>> def create(): ... return [lambda x: x * i for i in range(5)] ... >>> for i in create(): ... i(2) ... 8 8 8 8 8
這是後期綁定(late binding)致使的,這是指內層函數被執行時,纔會去查找該變量的值。請注意上面講的,for循環會致使變量泄漏,因此當函數執行的時候,i已經等於4了。
上面的代碼等價於:
>>> def create(): ... result = [] ... for i in range(5): ... def lala(x): ... return x * i ... result.append(lala) ... return result
再理解一次,內層函數lala在執行時,纔會去找i是多少,而執行的時候i已經等於4了。
解決方法:
>>> def create(): ... return [lambda x, y=i: x * y for i in range(5)] ... >>> for i in create(): ... i(2) ... 0 2 4 6 8
利用前面所講的,帶默認函數的函數將會在函數定義時完成賦值,來解決這個問題
未完成