首页 > Python基础教程 >
-
十个Python程序员易犯的错误(4)
常见错误6:不理解Python在闭包中如何绑定变量
请看下面这段代码:
1
2
3
4
5
|
>>> def create_multipliers(): ... return [lambda x : i * x for i in range(5)] >>> for multiplier in create_multipliers(): ... print multiplier(2) ... |
你可能觉得输出结果应该是这样的:
但是,实际的输出结果却是:
吓了一跳吧!
这个结果的出现,主要是因为Python中的迟绑定(late binding )机制,即闭包中变量的值只有在内部函数被调用时才会进行查询。因此,在上面的代码中,每次create_multipliers()所返回的函数被调用时,都会在附近的作用域中查询变量i的值(而到那时,循环已经结束,所以变量i最后被赋予的值为4)。
要解决这个常见Python问题的方法中,需要使用一些hack技巧:
1
2
3
4
5
6
7
8
9
10
11
|
>>> def create_multipliers(): ... return [lambda x, i=i : i * x for i in range(5)] ... >>> for multiplier in create_multipliers(): ... print multiplier(2) ... 0 2 4 6 8 |
请注意!我们在这里利用了默认参数来实现这个lambda匿名函数。有人可能认为这样做很优雅,有人会觉得很巧妙,还有人会嗤之以鼻。但是,如果你是一名Python程序员,不管怎样你都应该要了解这种解决方法。
常见错误7:模块之间出现循环依赖(circular dependencies)
假设你有两个文件,分别是a.py和b.py,二者相互引用,如下所示:
a.py文件中的代码:
1
2
3
4
|
import b def f(): return b.x print f() |
b.py文件中的代码:
1
2
3
4
|
import a x = 1 def g(): print a.f() |
首先,我们尝试导入a.py模块:
代码运行正常。也许这出乎了你的意料。毕竟,我们这里存在循环引用这个问题,想必应该是会出现问题的,难道不是吗?
答案是,仅仅存在循环引用的情况本身并不会导致问题。如果一个模块已经被引用了,Python可以做到不再次进行引用。但是如果每个模块试图访问其他模块定义的函数或变量的时机不对,那么你就很可能陷入困境。
那么回到我们的示例,当我们导入a.py模块时,它在引用b.py模块时是不会出现问题的,因为b.py模块在被引用时,并不需要访问在a.py模块中定义的任何变量或函数。b.py模块中对a模块唯一的引用,就是调用了a模块的foo()函数。但是那个函数调用发生在g()函数当中,而a.py或b.py模块中都没有调用g()函数。所以,不会出现问题。
但是,如果我们试着导入b.py模块呢(即之前没有引用a.py模块的前提下):
1
2
3
4
5
6
7
8
9
10
|
>>> import b Traceback (most recent call last): File "<stdin>" < /stdin >, line 1, in <module> File "b.py" , line 1, in <module> import a File "a.py" , line 6, in <module> print f() File "a.py" , line 4, in f return b.x AttributeError: 'module' object has no attribute 'x' |