首页 > Python基础教程 >
-
Python 程序员经常犯的 10 个错误(3)
这里出什么问题了?
上面的问题之所以会发生是因为当你给作用域中的一个变量赋值时,Python 会自动的把它当做是当前作用域的局部变量,从而会隐藏外部作用域中的同名变量。
很多人会感到很吃惊,当他们给之前可以正常运行的代码的函数体的某个地方添加了一句赋值语句之后就得到了一个 UnboundLocalError 的错误。 (你可以在这里了解到更多)
尤其是当开发者使用 lists 时,这个问题就更加常见. 请看下面这个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> lst = [ 1 , 2 , 3 ] >>> def foo1(): ... lst.append( 5 ) # 没有问题... ... >>> foo1() >>> lst [ 1 , 2 , 3 , 5 ] >>> lst = [ 1 , 2 , 3 ] >>> def foo2(): ... lst + = [ 5 ] # ... 但是这里有问题! ... >>> foo2() |
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'lst' referenced before assignment
嗯?为什么 foo2 报错,而foo1没有问题呢?
原因和之前那个例子的一样,不过更加令人难以捉摸。foo1 没有对 lst 进行赋值操作,而 foo2 做了。要知道, lst += [5] 是 lst = lst + [5] 的缩写,我们试图对 lst 进行赋值操作(Python把他当成了局部变量)。此外,我们对 lst 进行的赋值操作是基于 lst 自身(这再一次被Python当成了局部变量),但此时还未定义。因此出错!
常见错误 5:当迭代时修改一个列表(List)
下面代码中的问题应该是相当明显的:
1
2
3
4
5
6
|
>>> odd = lambda x : bool (x % 2 ) >>> numbers = [n for n in range ( 10 )] >>> for i in range ( len (numbers)): ... if odd(numbers[i]): ... del numbers[i] # BAD: Deleting item from a list while iterating over it ... |
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IndexError: list index out of range
当迭代的时候,从一个 列表 (List)或者数组中删除元素,对于任何有经验的开发者来说,这是一个众所周知的错误。尽管上面的例子非常明显,但是许多高级开发者在更复杂的代码中也并非是故意而为之的。
幸运的是,Python包含大量简洁优雅的编程范例,若使用得当,能大大简化和精炼代码。这样的好处是能得到更简化和更精简的代码,能更好的避免程序中出现当迭代时修改一个列表(List)这样的bug。一个这样的范例是递推式列表(list comprehensions)。而且,递推式列表(list comprehensions)针对这个问题是特别有用的,通过更改上文中的实现,得到一段极佳的代码:
1
2
3
4
5
|
>>> odd = lambda x : bool (x % 2 ) >>> numbers = [n for n in range ( 10 )] >>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all >>> numbers [ 0 , 2 , 4 , 6 , 8 ] |