Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用python中的lambda表达式在循环内生成函数_Python_Lambda_Scope - Fatal编程技术网

用python中的lambda表达式在循环内生成函数

用python中的lambda表达式在循环内生成函数,python,lambda,scope,Python,Lambda,Scope,如果我列出两个函数列表: def makeFun(i): return lambda: i a = [makeFun(i) for i in range(10)] b = [lambda: i for i in range(10)] 为什么列表a和b的行为不符合保存方式 例如: >>> a[2]() 2 >>> b[2]() 9 python中的lambda共享在其中创建它们的变量范围。在第一种情况下,lambda的范围是makeFun。在第二种

如果我列出两个函数列表:

def makeFun(i):
    return lambda: i

a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]
为什么列表
a
b
的行为不符合保存方式

例如:

>>> a[2]()
2
>>> b[2]()
9

python中的lambda共享在其中创建它们的变量范围。在第一种情况下,lambda的范围是makeFun。在第二种情况下,它是全局
i
,它是9,因为它是循环的剩余部分


这就是我对它的理解…

从技术上讲,lambda表达式在全局范围内可见的
I
上是闭合的,最后设置为9。这与所有10个lambda中引用的
i
相同。比如说,

i = 13
print b[3]()

makeFun
函数中,lambda在调用函数时定义的
i
上关闭。这是十种不同的
i
s.

很好的捕捉。列表中的lambda每次都看到相同的本地
i

您可以将其改写为:

a = []
for i in range(10):
    a.append(makefun(i))

b = []
for i in range(10):
    b.append(lambda: i)
具有相同的结果。

一组函数(a)对传递的参数进行操作,另一组函数(b)对全局变量进行操作,然后将全局变量设置为9。检查拆卸:

>>> import dis
>>> dis.dis(a[2])
  1           0 LOAD_DEREF               0 (i)
              3 RETURN_VALUE
>>> dis.dis(b[2])
  1           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE
>>>

正如其他人所说,范围界定是一个问题。请注意,可以通过向lambda表达式添加额外参数并为其指定默认值来解决此问题:

>> def makeFun(i): return lambda: i
... 
>>> a = [makeFun(i) for i in range(10)]
>>> b = [lambda: i for i in range(10)]
>>> c = [lambda i=i: i for i in range(10)]  # <-- Observe the use of i=i
>>> a[2](), b[2](), c[2]()
(2, 9, 2)
>def makeFun(i):返回lambda:i
... 
>>>a=[makeFun(i)代表范围(10)内的i]
>>>b=[lambda:i表示范围(10)内的i]
>>>c=[lambda i=i:i代表范围(10)]#>>a[2](),b[2](),c[2]()
(2, 9, 2)
结果是,
i
现在被明确地放在一个限定于
lambda
表达式的范围内。

以增加一些清晰性(至少在我看来)

a使用makeFun(i),这是一个带有参数的函数

b使用lambda:i,它是一个没有参数的函数。它使用的i与以前的i非常不同

要使a和b相等,我们可以使两个函数都不使用参数:

def makeFun(): return lambda: i
a = [makeFun() for i in range(10)]
b = [lambda: i for i in range(10)]
现在两个函数都使用全局i

>>> a[2]()
9
>>> b[2]()
9
>>> i=13
>>> a[2]()
13
>>> b[2]()
13
或者(更有用)使两者都使用一个参数:

def makeFun(x): return lambda: x
a = [makeFun(i) for i in range(10)]
b = [lambda x=i: x for i in range(10)]
我故意用x来改变I,其中变量是局部的。 现在:


成功

我不知道你想说什么。在您的示例中,
b[2]()
也返回9;不是说a和b是一样的。我认为拼写出的
for
循环将更容易看到
I
的来源。好了,现在这对我来说是有意义的。谢谢从Python3开始,列表理解现在有了自己的作用域。所以改变它的值不会改变print(b[3]())的输出。有关列表理解行为的更多详细信息,请参见
def makeFun(x): return lambda: x
a = [makeFun(i) for i in range(10)]
b = [lambda x=i: x for i in range(10)]
>>> a[2]()
2
>>> b[2]()
2