Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/301.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_Closures - Fatal编程技术网

Python lambda闭包作用域

Python lambda闭包作用域,python,lambda,closures,Python,Lambda,Closures,我试图使用闭包从函数签名中消除一个变量。应用程序将编写连接接口的Qt信号所需的所有函数,以控制大量参数到存储值的字典中 我不明白为什么使用lambda而不是包装在另一个函数中的情况会返回所有情况下的姓氏 names = ['a', 'b', 'c'] def test_fun(name, x): print(name, x) def gen_clousure(name): return lambda x: test_fun(name, x) funcs1 = [gen_cl

我试图使用闭包从函数签名中消除一个变量。应用程序将编写连接接口的Qt信号所需的所有函数,以控制大量参数到存储值的字典中

我不明白为什么使用lambda而不是包装在另一个函数中的情况会返回所有情况下的姓氏

names = ['a', 'b', 'c']

def test_fun(name, x):
    print(name, x)

def gen_clousure(name):
    return lambda x: test_fun(name, x)

funcs1 = [gen_clousure(n) for n in names]
funcs2 = [lambda x: test_fun(n, x) for n in names]

# this is what I want
In [88]: for f in funcs1:
   ....:     f(1)
a 1
b 1
c 1

# I do not understand why I get this
In [89]: for f in funcs2:
   ....:     f(1)
c 1
c 1
c 1

原因是闭包lambdas或其他闭包覆盖的是名称,而不是值。定义lambda x:test_funn,x时,不计算n,因为它位于函数内部。在调用函数时对其求值,此时存在的值是循环中的最后一个值

您在开始时说,您希望使用闭包从函数签名中消除变量,但实际上不是这样。不过,请参见下文,了解一种可能让您满意的方法,具体取决于您所说的“消除”是什么意思。定义函数时,不会计算函数体中的变量。为了让函数获取变量在函数定义时的快照,必须将变量作为参数传递。通常的方法是给函数一个参数,该参数的默认值是外部作用域中的变量。看看这两个例子之间的区别:

>>> stuff = [lambda x: n+x for n in [1, 2, 3]]
>>> for f in stuff:
...     print f(1)
4
4
4
>>> stuff = [lambda x, n=n: n+x for n in [1, 2, 3]]
>>> for f in stuff:
...     print f(1)
2
3
4
在第二个示例中,将n作为参数传递给函数会将n的当前值锁定到该函数。如果要以这种方式锁定值,必须执行类似的操作。如果不是这样的话,像全局变量这样的东西就根本不起作用了;在使用时查找自由变量是很重要的

请注意,有关此行为的任何内容都不是特定于lambdas的。如果使用def定义引用封闭范围内变量的函数,则相同的作用域规则有效

如果确实需要,可以避免向返回的函数中添加额外的参数,但要这样做,必须将该函数包装到另一个函数中,如下所示:

>>> def makeFunc(n):
...     return lambda x: x+n
>>> stuff = [makeFunc(n) for n in [1, 2, 3]]
>>> for f in stuff:
...     print f(1)
2
3
4
在这里,内部lambda在被调用时仍然查找n的值。但它所指的n不再是全局变量,而是封闭函数makeFunc中的局部变量。每次调用makeFunc时,都会创建此局部变量的新值,返回的lambda会创建一个闭包,该闭包保存在调用makeFunc时生效的局部变量值。因此,在循环中创建的每个函数都有自己的私有变量x。对于这个简单的例子,也可以使用lambda作为外部函数stuff=[lambda n:lambda x:x+nn作为[1,2,3]]中的n,但可读性较差

请注意,您仍然必须将n作为参数传递,只是这样做,您不会将它作为参数传递给最终进入材料列表的同一个函数;相反,您可以将其作为参数传递给一个帮助函数,该函数创建了要放入stuff中的函数。使用这种双函数方法的优点是,返回的函数是干净的,并且没有额外的参数;如果要包装接受大量参数的函数,这可能会很有用,在这种情况下,记住n参数在列表中的位置可能会变得混乱。这样做的缺点是,由于需要另一个封闭函数,因此生成函数的过程更加复杂


结果是有一个折衷:您可以使函数创建过程更简单,即不需要两个嵌套函数,但必须使生成的函数更复杂,即它有这个额外的n=n参数。或者,您可以使函数更简单,即它没有n=n参数,但必须使函数创建过程更复杂,即需要两个嵌套函数来实现该机制。

这是对这种Python行为的更好解释,而不是用