最近我开始玩Python,我遇到了一些特殊的闭包方式.请考虑以下代码:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Run Code Online (Sandbox Code Playgroud)
它构建了一个简单的函数数组,它接受单个输入并返回由数字添加的输入.函数在for循环中构造,迭代器i从中循环0到3.对于这些数字中的每一个,lambda都会创建一个函数i,该函数捕获并将其添加到函数的输入中.最后一行将第二个lambda函数3作为参数调用.令我惊讶的是输出结果是6.
我期待一个4.我的理由是:在Python中,一切都是一个对象,因此每个变量都是指向它的指针.在创建lambda闭包时i,我希望它存储一个指向当前指向的整数对象的指针i.这意味着当i分配一个新的整数对象时,它不应该影响先前创建的闭包.遗憾的是,adders在调试器中检查数组表明它确实存在.所有的lambda功能指的最后一个值i,3,这将导致adders[1](3)返回6.
这让我想知道以下内容:
lambda函数以更改其值i时不会受到影响的方式捕获当前i值?我想从Python中的常量列表中创建一个lambda对象列表; 例如:
listOfNumbers = [1,2,3,4,5]
square = lambda x: x * x
listOfLambdas = [lambda: square(i) for i in listOfNumbers]
Run Code Online (Sandbox Code Playgroud)
这将创建一个lambda对象列表,但是,当我运行它们时:
for f in listOfLambdas:
print f(),
Run Code Online (Sandbox Code Playgroud)
我希望它会打印出来
1 4 9 16 25
Run Code Online (Sandbox Code Playgroud)
相反,它打印:
25 25 25 25 25
Run Code Online (Sandbox Code Playgroud)
似乎lambdas都被赋予了错误的参数.我做错了什么,有没有办法解决它?我认为我在Python 2.4中.
编辑:更多的尝试事情,并提出了这样的想法:
listOfLambdas = []
for num in listOfNumbers:
action = lambda: square(num)
listOfLambdas.append(action)
print action()
Run Code Online (Sandbox Code Playgroud)
将预期的正方形从1打印到25,然后使用之前的print语句:
for f in listOfLambdas:
print f(),
Run Code Online (Sandbox Code Playgroud)
仍然给了我所有25的.现有的lambda对象在这两个打印调用之间是如何变化的?
相关问题:为什么map()和列表理解的结果不同?
根据我的编程语言课程,在使用词法范围的语言中
函数体是在定义函数的环境中计算的,而不是在调用函数的环境中。
例如,SML 遵循以下行为:
val x = 1
fun myfun () =
x
val x = 10
val res = myfun() (* res is 1 since x = 1 when myfun is defined *)
Run Code Online (Sandbox Code Playgroud)
另一方面,Python 不遵循这种行为:
x = 1
def myfun():
return x
x = 10
myfun() # 10 since x = 10 when myfun is called
Run Code Online (Sandbox Code Playgroud)
那么为什么Python 被描述为使用词法作用域呢?