Python 陷阱

1. 可变的默认参数

  错误示例

>>> def lala(l=[]):
...     l.append(123)
...     print l
... 
>>> lala()
[123]
>>> lala()
[123, 123]
>>> lala()
[123, 123, 123]

  原因是,一个函数的默认值,仅在函数被定义时赋值一次。

  解决方法

>>> def lala(l=None):
...     if l is None:
...         l = []
...     l.append(123)
...     print l
... 
>>> lala()
[123]
>>> lala()
[123]
>>> lala([456])
[456, 123]

 

2. 闭包问题

  问题1:期望得到一个每执行一次,数字加1的函数

  错误示例

>>> 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(见《命名空间与作用域》)

  正确的做法

>>> def counter():
...     count = [0]
...     def func():
...         count[0] += 1
...         print count[0]
...     return func
... 
>>> lala = counter()
>>> lala()
1
>>> lala()
2

  因为在list是可变对象,因此可以巧妙的跳过这个限制。

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

  利用前面所讲的,带默认函数的函数将会在函数定义时完成赋值,来解决这个问题

 

  未完成

posted @ 2016-04-29 17:35  Selol  阅读(336)  评论(0编辑  收藏  举报