最近我开始玩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值?我需要一个回调函数,对于一系列gui事件几乎完全相同.该函数的行为会略有不同,具体取决于调用它的事件.对我来说似乎是一个简单的案例,但我无法弄清楚lambda函数的这种奇怪的行为.
所以我在下面有以下简化代码:
def callback(msg):
print msg
#creating a list of function handles with an iterator
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(lambda: callback(m))
for f in funcList:
f()
#create one at a time
funcList=[]
funcList.append(lambda: callback('do'))
funcList.append(lambda: callback('re'))
funcList.append(lambda: callback('mi'))
for f in funcList:
f()
Run Code Online (Sandbox Code Playgroud)
此代码的输出是:
mi
mi
mi
do
re
mi
Run Code Online (Sandbox Code Playgroud)
我期望:
do
re
mi
do
re
mi
Run Code Online (Sandbox Code Playgroud)
为什么使用迭代器搞砸了?
我尝试过使用深度镜:
import copy
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(lambda: callback(copy.deepcopy(m)))
for f in funcList:
f()
Run Code Online (Sandbox Code Playgroud)
但这也存在同样的问题.
我正在尝试在循环内创建函数并将它们存储在字典中.问题是字典中的所有条目似乎最终都映射到最后创建的函数.代码如下:
functions = []
for i in range(3):
def f():
return i
# alternatively: f = lambda: i
functions.append(f)
Run Code Online (Sandbox Code Playgroud)
这输出:
print([f() for f in functions])
# expected output: [0, 1, 2]
# actual output: [2, 2, 2]
Run Code Online (Sandbox Code Playgroud)
知道为什么吗?
代码说明更多:
from pprint import pprint
li = []
for i in range(5):
li.append(lambda : pprint(i))
for k in li:
k()
Run Code Online (Sandbox Code Playgroud)
让:
4 4 4 4 4
为什么不
0 1 2 3 4
??
谢谢.
PS如果我写完整的装饰器,它按预期工作:
from pprint import pprint
li = []
#for i in range(5):
#li.append(lambda : pprint(i))
def closure(i):
def _func():
pprint(i)
return _func
for i in range(5):
li.append(closure(i))
for k in li:
k()
Run Code Online (Sandbox Code Playgroud) 我在Python hitchhikers 指南中看到了这个例子:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
Run Code Online (Sandbox Code Playgroud)
上面的示例是对后期绑定引起的一些问题的解决方案,其中在调用内部函数时查找闭包中使用的变量。
i=i 是什么意思以及为什么会产生如此大的差异?
今天我探讨了Python 的奇怪行为.一个例子:
closures = []
for x in [1, 2, 3]:
# store `x' in a "new" local variable
var = x
# store a closure which returns the value of `var'
closures.append(lambda: var)
for c in closures:
print(c())
Run Code Online (Sandbox Code Playgroud)
上面的代码打印出来
3
3
3
Run Code Online (Sandbox Code Playgroud)
但是我希望它能打印出来
1
2
3
Run Code Online (Sandbox Code Playgroud)
我为自己解释了这种行为,var它始终是相同的局部变量(并且python不像其他语言那样创建新的行为).如何修复上面的代码,以便每个闭包都返回另一个值?
我想在我的类中定义许多方法TestClass。我想呼唤他们的名字TestClass().method_1......TestClass().method_n
我不想间接调用它们,例如通过中间方法来TestClass().use_method('method_1', params)保持与代码其他部分的一致性。
我想动态定义我的众多方法,但我不明白为什么这个最小的示例不起作用:
class TestClass:
def __init__(self):
method_names = [
'method_1',
'method_2']
for method_name in method_names:
def _f():
print(method_name)
# set the method as attribute
# (that is OK for me that it will not be
# a bound method)
setattr(
self,
method_name,
_f)
del _f
if __name__ == '__main__':
T = TestClass()
T.method_1()
T.method_2()
print(T.method_1)
print(T.method_2)
Run Code Online (Sandbox Code Playgroud)
输出是:
function_2
function_2
<function TestClass.__init__.<locals>._f at 0x0000022ED8F46430>
<function TestClass.__init__.<locals>._f at 0x0000022EDADCE4C0>
Run Code Online (Sandbox Code Playgroud)
当我期待的时候
function_1
function_2
Run Code Online (Sandbox Code Playgroud)
我尝试在很多地方放置一些 …
我正在尝试创建一个函数(函数对象)列表,从另一个列表中打印出相应的项目:
strings = ["a", "b", "c"]
functions = []
for i in strings:
functions.append(lambda: print(i))
Run Code Online (Sandbox Code Playgroud)
上面的代码的作用是创建 lambda 函数,该函数在调用时会打印 i 的值。我希望字符串列表和函数列表的项目具有一对一的关系,这意味着我想要以下结果。
输出1:
>>> functions[0]()
'a'
>>> functions[1]()
'b'
>>> functions[2]()
'c'
Run Code Online (Sandbox Code Playgroud)
但我得到这个:
输出2:
>>> functions[0]()
'c'
>>> functions[1]()
'c'
>>> functions[2]()
'c'
Run Code Online (Sandbox Code Playgroud)
我知道 for 循环中的变量 i 在循环结束后仍然存在,并且所有函数最终都会打印出相同的 i 值。
有没有办法让函数打印出字符串列表的相应值,就像上面的Output1一样?