Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.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_Loops_Anonymous Function - Fatal编程技术网

Python 循环中的Lambda

Python 循环中的Lambda,python,loops,anonymous-function,Python,Loops,Anonymous Function,考虑以下代码段: # directorys == {'login': <object at ...>, 'home': <object at ...>} for d in directorys: self.command["cd " + d] = (lambda : self.root.change_directory(d)) 但看起来生成的两个lambda函数完全相同: # Result : self.command == { &q

考虑以下代码段:

# directorys == {'login': <object at ...>, 'home': <object at ...>}
for d in directorys:
    self.command["cd " + d] = (lambda : self.root.change_directory(d))
但看起来生成的两个lambda函数完全相同:

# Result :
self.command == {
    "cd login": lambda: self.root.change_directory("login"),
    "cd home": lambda: self.root.change_directory("login")   # <- Why login ?
}
#结果:
self.command=={
“cd登录”:lambda:self.root.change_目录(“登录”),

“cd home”:lambda:self.root.change_directory(“login”)#这是由于绑定d的点。lambda函数都指向变量
d
,而不是它的当前值,因此在下一次迭代中更新
d
时,会在所有函数中看到此更新

举一个简单的例子:

funcs = []
for x in [1,2,3]:
  funcs.append(lambda: x)

for f in funcs:
  print f()

# output:
3
3
3
您可以通过添加一个附加函数来解决此问题,如下所示:

def makeFunc(x):
  return lambda: x

funcs = []
for x in [1,2,3]:
  funcs.append(makeFunc(x))

for f in funcs:
  print f()

# output:
1
2
3
还可以修复lambda表达式内的作用域

lambda bound_x=x: bound_x

但是,一般来说,这不是一个好的做法,因为您已经更改了函数的签名。

您需要为创建的每个函数绑定d。一种方法是将其作为参数传递,并使用默认值:

lambda d=d: self.root.change_directory(d)
现在,函数中的d使用参数,即使它具有相同的名称,并且在创建函数时会计算该参数的默认值。要帮助您查看以下内容:

lambda bound_d=d: self.root.change_directory(bound_d)
记住默认值是如何工作的,例如对于列表和dict之类的可变对象,因为您正在绑定一个对象

这种使用默认值的参数的习惯用法很常见,但如果您反思函数参数并根据它们的存在确定要执行的操作,则可能会失败。您可以使用另一个闭包来避免该参数:

(lambda d=d: lambda: self.root.change_directory(d))()
# or
(lambda d: lambda: self.root.change_directory(d))(d)

我遇到了同样的问题。所选的解决方案对我帮助很大,但是我认为有必要增加一个精度来使问题的代码功能化:在循环之外定义lambda函数。顺便说一下,缺省值不是必需的。

foo = lambda d: lambda : self.root.change_directory(d)
for d in directorys:
    self.command["cd " + d] = (foo(d))

或者,在我看来,可以使用更简洁的语法,而不是
lambda

而不是:

for d in directorys:
    self.command["cd " + d] = (lambda d=d: self.root.change_directory(d))
它将是:

for d in directorys:
    self.command["cd " + d] = partial(self.root.change_directory, d)

或者,这里是另一个简单的例子:

numbers = [1, 2, 3]

lambdas = [lambda: print(number) 
           for number in numbers]
lambdas_with_binding = [lambda number=number: print(number) 
                        for number in numbers]
partials = [partial(print, number) 
            for number in numbers]

for function in lambdas:
    function()
# 3 3 3
for function in lambdas_with_binding:
    function()
# 1 2 3
for function in partials:
    function()
# 1 2 3

我没有意识到lambda中允许使用默认值。将带有默认参数的lambda作为关键字参数传递看起来很奇怪:
command=lambda path=path:selected(path)
。使用
def
在for循环中定义闭包时会出现同样的问题吗?在Python中for循环没有自己的作用域吗?这显然是一种更好的方法,我会在机会出现时推荐它。
lambda x=x
技巧不仅仅是不直观的,它利用了相同的行为.Binding参数使用
functools.partial
是显式的,而且(这使它更加枯燥)。哦,默认参数也可以被覆盖,但不应该被覆盖-这是一个潜在的陷阱。像将外部变量绑定到partial for lambda这样的问题是ruby的一个副作用,因为ruby在任何地方都不可用。
numbers = [1, 2, 3]

lambdas = [lambda: print(number) 
           for number in numbers]
lambdas_with_binding = [lambda number=number: print(number) 
                        for number in numbers]
partials = [partial(print, number) 
            for number in numbers]

for function in lambdas:
    function()
# 3 3 3
for function in lambdas_with_binding:
    function()
# 1 2 3
for function in partials:
    function()
# 1 2 3