gpt4 book ai didi

python - 如何使用循环创建一致的Lambda函数?

转载 作者:太空宇宙 更新时间:2023-11-03 16:50:30 24 4
gpt4 key购买 nike

我想创建几个类似的lambda函数。

当我使用一个简单的循环时,我不会得到我期望的结果。

码:

funcList = []
for i in range(2):
f = lambda x: i*x
print("Before: ", f(10))
funcList.append(f)

print("After: ", funcList[0](10), funcList[1](10))


输出:

Before:  0
Before: 10
After: 10 10


码:

funcList = [lambda x: i*x for i in range(2)]
print("After: ", funcList[0](10), funcList[1](10))


输出:

After:  10 10


如何使用 i的“原始”值而不是 i的最后一个已知值创建几个lambda函数?

最佳答案

问题如下:Python中的闭包(请参见lambdas vs closures)关闭其环境,该环境将变量名映射到对象,并且它们实际上是通过将闭合环境添加到其范围查找链来实现的。考虑一个更简单,更明确的示例:

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...}


也就是说,如果 foo尝试使用变量 z,则它首先在第一个环境( foo的局部变量)中查找。如果存在,则查找成功。如果不是,它将移至下一个(全局变量)。如果存在,则查找成功。如果没有,那么链上就没有其他环境,因此您会得到一个 NameError

在这种情况下, resulti将被发现为局部变量, foosys可能还会被发现为全局变量,而其他所有变量都将被赋予 NameError

每个 bar中的作用域查找链类似于:

- "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...}


最重要的是, 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...}


但是,当 foo更改其局部变量 i时,bar的范围查找链现在如下所示:

- "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查找 i时,它再次无法在其局部变量中找到它,在范围查找链中查找一个,并找到 foo的局部变量 i ...现在为1因为它和以前一样 i



我在评论中写的俩有点a。为了更明确一点,请考虑:

def foo():
result = []
for i in range(2):
def bar(j=i):
return j
result.append(bar)
return result


真正发生的是,您使用参数 bar声明了 j,其默认设置为 i的值(即 i在定义时引用的对象... i随时使用 j引用的对象)。因此,第一个 bar函数的作用域查找链如下所示:

- "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的局部变量中成功进行,并且 bar永不改变。



执行以下操作有点麻烦,因为它只是隐藏了外部 j并使其看起来像是在引用同一 i

def foo():
result = []
for i in range(2):
def bar(i=i):
return i
result.append(bar)
return result


但实际上,它们是两个不同的 i

- "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...}




可能更“合适”的方法是执行以下操作:

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


在这种情况下,作用域链为:

- "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: {}
- "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_bar调用的,调用 i时将其局部变量 make_bar设置为 j在调用时引用的对象(即 i)。当 0make_bar更改时, j的局部变量 foo不会更改。



要针对您的情况做一个完全明确的示例,您可以执行以下操作:

funcList = []
for i in range(2):
def make_f(j):
def f(x):
return j * x
funcList.append(make_f(i))


或者,作为 @ShadowRanger commented

funcList = []
for i in range(2):
funcList.append((lambda j: lambda x: j*x)(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)]

关于python - 如何使用循环创建一致的Lambda函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35882273/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com