VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 十个Python程序员易犯的错误(3)

出了什么问题?

上述错误的出现,是因为当你在某个作用域内为变量赋值时,该变量被Python解释器自动视作该作用域的本地变量,并会取代任何上一层作用域中相同名称的变量。

正是因为这样,才会出现一开始好好的代码,在某个函数内部添加了一个赋值语句之后却出现了UnboundLocalError,难怪会让许多人吃惊。

在使用列表时,Python程序员尤其容易陷入这个圈套。

请看下面这个代码示例:

1
2
3
4
5
6
7
>>> lst = [1, 2, 3]
>>> def foo1():
...   lst.append(5)  # 这里没问题
...
>>> foo1()
>>> lst
[1, 2, 3, 5]
1
2
3
4
5
6
7
8
9
>>> lst = [1, 2, 3]
>>> def foo2():
...   lst += [5]   # ... 但这里就不对了!
...
>>> foo2()
Traceback (most recent call last):
 File "<stdin>"</stdin>, line 1, in <module>
 File "<stdin>"</stdin>, line 2, in foo
UnboundLocalError: local variable 'lst' referenced before assignment

呃?为什么函数foo1运行正常,foo2却出现了错误?

答案与上一个示例相同,但是却更难捉摸清楚。foo1函数并没有为lst变量进行赋值,但是foo2却有赋值。我们知道,lst += [5]只是lst = lst + [5]的简写,从中我们就可以看出,foo2函数在尝试为lst赋值(因此,被Python解释器认为是函数本地作用域的变量)。但是,我们希望为lst赋的值却又是基于lst变量本身(这时,也被认为是函数本地作用域内的变量),也就是说该变量还没有被定义。这才出现了错误。

常见错误5:在遍历列表时更改列表

下面这段代码的问题应该算是十分明显:

1
2
3
4
5
6
7
8
9
>>> odd = lambda x : bool(x % 2)
>>> numbers = [n for in range(10)]
>>> for 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>"</stdin>, line 2, in <module>
IndexError: list index out of range

在遍历列表或数组的同时从中删除元素,是任何经验丰富的Python开发人员都会注意的问题。但是尽管上面的示例十分明显,资深开发人员在编写更为复杂代码的时候,也很可能会无意之下犯同样的错误。

幸运的是,Python语言融合了许多优雅的编程范式,如果使用得当,可以极大地简化代码。简化代码还有一个好处,就是不容易出现在遍历列表时删除元素这个错误。能够做到这点的一个编程范式就是列表解析式。而且,列表解析式在避免这个问题方面尤其有用,下面用列表解析式重新实现上面代码的功能:

1
2
3
4
5
>>> odd = lambda x : bool(x % 2)
>>> numbers = [n for in range(10)]
>>> numbers[:] = [n for in numbers if not odd(n)] # ahh, the beauty of it all
>>> numbers
[0, 2, 4, 6, 8]

相关教程