1. 迭代时修改一个列表
删除列表中的奇数
>>>numbers = [i for i in range(10)]>>>numbers[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>>odd = lambda x: bool(x%2)>>>for i in range(len(numbers)):... if odd(i):... del numbers[i]IndexError: list assignment index out of range
迭代时,从一个列表(List)或数组中删除元素,这是一个总所周知的错误。尽管上述程序的错误十分明显,但在开发某些大型程序时,有时则并非那么故意而为之。
幸运的是,python包含大量简洁而优雅的编程范式,若使用得当,将大大简化代码。针对上例,一个优雅的范例是通过递推式列表(list comprehensions):
>>>evens = [i for i in numbers if not odd(i)]>>>evens[0, 2, 4, 8]
2. 滥用表达式作为函数参数的默认值
def foo(bar=[]):bar.append('baz')return bar>>>foo()['baz']>>>foo()['baz', 'baz']>>>foo()['baz', 'baz', 'baz']
这段代码的错误之处在于误以为:函数在没有指定形参时总是将形参设置为默认值,然而事实并非如此,对这段代码的调试以及如何使用PyCharm可参看之前的一篇文章<Python 基础——一张图告诉你PyCharm如何进行断点调试>。
正确的形式如下:
def foo(bar=None):if not bar:bar = []bar.append('baz')return bar>>>foo()['baz']>>>foo()['baz']>>>foo()['baz']
3. 不明白闭包环境变量的绑定时机
理解Python闭包与延迟绑定
闭包:把函数当做一个对象,因此可以作为某个函数的返回值。同时闭包必须满足下列三个条件:
必须是一个嵌套的函数。闭包必须返回嵌套函数。嵌套函数必须引用一个外部的非全局的局部自由变量。
def create_multipliers():return [lambda x: i*x for i in range(5)]# 符合闭包的三个条件:存在嵌套函数且将嵌套函数返回,引用了一个非全局的局部自由变量 i;>>>for multiplier in create_mupliiers(5):... print(multiplier(2))...
期望输出的结果:
0248
然而输出的结果是:
88888
只是因为python的迟绑定
——闭包中用到的环境变量(闭包所依赖的变量)只有在函数被调用时才会被赋值,在上述的代码中,任何时候,当返回的函数被调用时,Python会在该函数被调用时的作用域中查找i对应的值(此时循环已经结束,i被附上了最终的值4)
解决方案:
def multipliers():return [lambda x, i=i: i*x for i in range(5)]>>>for multiplier in multipliers():... print(multiplier(2))...0248
利用默认参数生成匿名函数,以实现我们想要的结果。