Python 基础 —— Python程序员常犯的那些错误

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可参看之前的一篇文章

正确的形式如下:

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))
...

期望输出的结果:

0
2
4
8

然而输出的结果是:

8
8
8
8
8

只是因为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))
...
0
2
4
8

利用默认参数生成匿名函数,以实现我们想要的结果。

你可能感兴趣的:(python,面试)