Python 如何使用循环创建一致的lambda函数?
我想创建几个类似的lambda函数 当我使用一个简单的循环时,我没有得到我所期望的 代码: 输出:Python 如何使用循环创建一致的lambda函数?,python,lambda,Python,Lambda,我想创建几个类似的lambda函数 当我使用一个简单的循环时,我没有得到我所期望的 代码: 输出: Before: 0 Before: 10 After: 10 10 After: 10 10 代码: 输出: Before: 0 Before: 10 After: 10 10 After: 10 10 如何使用I的“原始”值而不是I的最后一个已知值创建多个lambda函数?这是由于后期绑定 您已经创建了一个包含2个函数的列表 这些功能是什么乐趣(x):返回i*x 在这个阶
Before: 0
Before: 10
After: 10 10
After: 10 10
代码:
输出:
Before: 0
Before: 10
After: 10 10
After: 10 10
如何使用
I
的“原始”值而不是I
的最后一个已知值创建多个lambda函数?这是由于后期绑定
funcList[0](10)
时,它将返回i*xfuncList[0](10)
的所有调用都将返回10注释
f=lambda x,i=i:i*x
中已经给出了答案,这将避免后期绑定,i的值将在创建函数对象时解析 问题如下:Python中的闭包(请参阅)关闭其环境,将变量名映射到对象,它们通过将关闭的环境添加到其作用域查找链来实现这一点。考虑一个更简单、更明确的例子:
import sys
def foo():
result = []
for i in range(2):
def bar():
return i
result.append(bar)
return result
foo
的作用域查找链(在返回之前包含环境)类似于:
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
def make_bar(j):
def bar():
return j
return bar
def foo():
result = []
for i in range(2):
bar = make_bar(i)
result.append(bar)
return result
funcList = []
for i in range(2):
def make_f(j):
def f(x):
return j * x
funcList.append(make_f(i))
也就是说,如果foo
尝试使用变量z
,首先它会在第一个环境中查找(foo
的局部变量)。如果存在,则查找成功。如果没有,它将移动到下一个(全局变量)。如果存在,则查找成功。如果没有,那么链上就没有更多的环境,因此会出现namererror
在这种情况下,result
和i
将被发现作为局部变量,foo
和sys
也许其他变量将被发现作为全局变量,所有其他变量将给出一个namererror
每个栏中的范围查找链类似于:
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
def make_bar(j):
def bar():
return j
return bar
def foo():
result = []
for i in range(2):
bar = make_bar(i)
result.append(bar)
return result
funcList = []
for i in range(2):
def make_f(j):
def f(x):
return j * x
funcList.append(make_f(i))
最重要的是,foo
的局部变量环境不会复制到bar
的局部变量环境中。因此,bar
可以查找i
,但是它首先在bar
的局部变量中找不到它,然后在作用域链上找到一个,然后在foo
的局部变量中找到它。因此,当定义第一个bar
函数时,其范围查找链如下所示:
- "bar" local variables: {}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
但是,当foo
更改其局部变量i
时,bar的范围查找链现在如下所示:
- "bar" local variables: {}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
因此,现在当bar
查找i
时,它再次无法在其局部变量中找到它,在范围查找链中查找一个,并找到foo
的局部变量i
。。。现在是1,因为它与以前的i
相同
我在评论中写的诀窍有点老套。为了更明确一点,请考虑:
def foo():
result = []
for i in range(2):
def bar(j=i):
return j
result.append(bar)
return result
实际情况是,您正在使用参数j
声明bar
,其默认值设置为i
的值(即i
在定义时引用的对象…而不是i
在任何时候引用的对象j
在bar
内部使用)。因此,第一个条
函数处的范围查找链如下所示:
- "bar" local variables: {}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
当循环再次循环时,它看起来是这样的:
- "bar" local variables: {}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {j: 0}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
在这两种情况下,在bar
的局部变量中查找j
会立即成功,并且j
不会改变
执行以下操作有点麻烦,因为它只是隐藏了外部的i
,使它看起来像是在引用同一个i
:
def foo():
result = []
for i in range(2):
def bar(i=i):
return i
result.append(bar)
return result
但实际上,它们是两个不同的i
s:
- "bar" local variables: {i: 0}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {foo: foo-function, sys: sys-module, etc...}
在循环的第二次迭代中:
- "bar" local variables: {i: 0}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "make_bar" local variables: {j: 0}
- "foo" local variables: {i: 1, result: [], bar: bar-function-2}
- global variables: {make_bar: make_bar-function, foo: foo-function, sys: sys-module, etc...}
可能更“恰当”的方法是做以下事情:
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
def make_bar(j):
def bar():
return j
return bar
def foo():
result = []
for i in range(2):
bar = make_bar(i)
result.append(bar)
return result
funcList = []
for i in range(2):
def make_f(j):
def f(x):
return j * x
funcList.append(make_f(i))
在这种情况下,范围链是:
- "bar" local variables: {}
- "make_bar" local variables: {j: 0}
- "foo" local variables: {i: 0, result: [], bar: bar-function-1}
- global variables: {make_bar: make_bar-function, foo: foo-function, sys: sys-module, etc...}
在循环的第二次迭代中:
- "bar" local variables: {i: 0}
- "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "make_bar" local variables: {j: 0}
- "foo" local variables: {i: 1, result: [], bar: bar-function-2}
- global variables: {make_bar: make_bar-function, foo: foo-function, sys: sys-module, etc...}
在这种情况下,它起作用是因为用i
调用make\u bar
,调用make\u bar
将其局部变量j
设置为调用时i
引用的对象(即0
)<当foo
的i
更改时,code>make_-bar
的局部变量j
不会更改
在您的案例中,要做一个完全明确的示例,您可以做如下操作:
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
- "bar" local variables: {}
- "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
- global variables: {foo: foo-function, sys: sys-module, etc...}
def make_bar(j):
def bar():
return j
return bar
def foo():
result = []
for i in range(2):
bar = make_bar(i)
result.append(bar)
return result
funcList = []
for i in range(2):
def make_f(j):
def f(x):
return j * x
funcList.append(make_f(i))
或者,作为:
或者只是:
funcList = [(lambda j: lambda x: j*x)(i) for i in range(2)]
或者你也可以使用我提出的黑客,现在你已经知道了它的全部原理:
funcList = [lambda x, i=i: i*x for i in range(2)]
f=lambda x,i=i:i*x
@Claudiu,真管用!但是为什么…?闭包魔术。通过这种方式,您可以强制lambda引入带有局部作用域的i
,而不是使用外部作用域的i
@Felk:Claudiu的解决方案不是基于闭包的,它利用函数原型在定义时进行绑定,而函数体在调用时进行绑定。基于闭包的将是f=(lambda i:lambda x:i*x)(i)
;它的输入时间更长,稍微复杂一些,但与使用默认参数不同,它通过传递第二个参数消除了调用方更改i
的风险。哦,你说得对,对不起