第一,以下程序的执行结果是什么?
def foo(a = []):
a.append(1)
print a
foo()foo()
第二,以下程序的执行结果是什么?
def foo():
a = 1
def bar():
a += 1
print a return bar
func = foo()func()
第三,以下程序的执行结果是什么?
l = [x for x in xrange(10)]print x
d = {x : 2 * x for x in xrange(5)}print x
第一题的答案是
[1]
[1, 1]
这是因为,在Python中,Function是一种Object,所以foo函数其实是一个FunctionObject,它的默认参数是与这个Object绑定在一起的。所以,每次调用,所使用的参数a其实是同一个list对象。
第二题,运行会出现traceback。
出现这个的原因是因为Python编译器写得太简单了。它并没有合理地处理所有变量的scope。我们希望产生一个闭包,在bar方法里可以看得到它外面的变量。但是,实际上,我们得到的Python字节码是这样的:
LOAD_FAST aLOAD_CONST 1INPLACE_ADD
问题就出在这个LOAD_FAST上,我们知道,正确的闭包所使用的字节码其实应该是LOAD_CLOSURE。但在这里,因为在bar方法里,对a进行了赋值,所以编译器就把a当做了局部变量。访问一个未定义的局部变量当然就是错的了。
要想在Python里使用闭包,正确的做法是:
def foo():
a = [1]
def bar():
a[0] += 1
print a[0]
return bar
func = foo()func()func()
第三题,在2.7里,可以正确运行。结果是9, 9。
在2.6的时代,只支持列表推导式,字典推导式还没有得到支持。所以,如果你在2.6上运行这段程序,是会报错的。其实,在2.6的列表推导式的实现中,有一个设计缺陷,那就是循环变量x会污染外层的命名空间。也就是说,我执行完列表推导式以后,x 会进到程序的locals表里。而在2.7里,在实现字典表达式的时候,却又把这个循环变量做为局部变量处理了。所以离开了推导式,这个x就消失不见了。同时,2.7没有修复2.6的这个问题。所以就会出现上面所说的问题了。