Python 陷阱

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

  利用前面所講的,帶默認函數的函數將會在函數定義時完成賦值,來解決這個問題

 

  未完成

相關文章
相關標籤/搜索