Python lambda 函数访问外部变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21053988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
lambda function acessing outside variable
提问by Hovestar
I wanted to play around with anonymous functions so I decided to make a simple prime finder. Here it is:
我想玩弄匿名函数,所以我决定制作一个简单的素数查找器。这里是:
tests = []
end = int(1e2)
i = 3
while i <= end:
a = map(lambda f:f(i),tests)
if True not in a:
tests.append(lambda x:x%i==0)
print i
print tests
print "Test: "+str(i)
print str(a)
i+=2
What I find however, is that the iin the lambda x:x%i==0is accessed each time, while i want it to be a literal number. how can I get it to become lambda x:x%3==0instead?
然而,我发现每次都访问iin lambda x:x%i==0,而我希望它是一个文字数字。我怎样才能让它变成lambda x:x%3==0呢?
采纳答案by Ryan Haining
You can "capture" the iwhen creating the lambda
您可以i在创建 lambda 时“捕获”
lambda x, i=i: x%i==0
This will set the iin the lambda's context equal to whatever iwas when it was created. you could also say lambda x, n=i: x%n==0if you wanted, it's not exactly capture, but it gets you what you need.
这会将ilambda 上下文中的设置为等于i创建时的任何内容。您也可以说,lambda x, n=i: x%n==0如果您愿意,它并不完全是捕获,但它可以为您提供所需的东西。
It's an issue of lookup that's analogous to the following with defined functions:
这是一个查找问题,类似于以下定义的函数:
i = "original"
def print_i1():
print(i) # prints "changed" when called below
def print_i2(s=i): #default set at function creation, not call
print(s) # prints "original" when called below
i = "changed"
print_i1()
print_i2()
回答by user2864740
Create a new function that returns the lambda. Then call that, passing in ias an argument. This will create a new binding scope.
创建一个返回 lambda 的新函数。然后调用它,i作为参数传入。这将创建一个新的绑定范围。
def make_test (i):
# this i refers to the parameter (which evaluates to the /value/ passed)
return lambda x: x%i==0
# ..
# the /value/ resulting from evaluating the variable is passed
tests.append(make_test(i))
回答by abarnert
The problem is that each of those functions in testsis referring to the variable i.
问题是这些函数中的每一个tests都指向变量i。
More commonly, you do this inside a function, in which case you have a local-to-the-defining-scope variable i, which gets stored in a closure, as nicely explained in These Nasty Closures.
更常见的是,您在一个函数中执行此操作,在这种情况下,您有一个本地到定义范围的变量i,该变量存储在一个闭包中,正如这些讨厌的闭包中很好地解释的那样。
But here, it's even simpler: iis a global variable, so there is no closure. The functions are compiled to look up ias a global variable when run. Since ihas changed, the functions will see the changed value when they run. Simple as that.
但在这里,它更简单:i是一个全局变量,所以没有闭包。这些函数被编译为i在运行时查找为全局变量。由于i已更改,函数在运行时将看到更改的值。就那么简单。
The traditional way around this (which works for both closures and globals) is fondly known as "the default-value hack", even though it's not really a hack. (See the explanation in the FAQ.) Ryan Haining's answer explains how to do this:
解决这个问题的传统方法(适用于闭包和全局变量)被亲切地称为“默认值黑客”,尽管它并不是真正的黑客。(请参阅FAQ 中的解释。)Ryan Haining 的回答解释了如何执行此操作:
lambda x, i=i: x%i==0
This creates a parameter named i, with a default value equal to the value of iat the time the function is created. Then, inside the function, when you access parameter i, and you get that value.
这将创建一个名为 的参数i,其默认值等于i创建函数时的值。然后,在函数内部,当您访问 parameter 时i,您将获得该值。
A different way around this, which may seem more familiar if you're using to languages like JavaScript, is to create a function-creating function, and pass the value of ias an argument to that function-creating function, as in user2864740's answer:
解决此问题的另一种方法(如果您使用 JavaScript 之类的语言可能看起来更熟悉)是创建一个函数创建函数,并将 的值i作为参数传递给该函数创建函数,如 user2864740 的回答:
(lambda i: lambda x: x%i)(i)
This avoids "polluting" the signature of the function with an extra parameter (that someone could accidentally pass an argument to), but at the cost of creating and calling a function for no good reason.
这避免了使用额外参数(有人可能会不小心将参数传递给)“污染”函数的签名,但代价是无缘无故地创建和调用函数。
A third way around this is to use partial. In cases where all you're trying to do is partially apply a function, using partialinstead of defining a wrapper function as a lambdacan be cleaner.
解决此问题的第三种方法是使用partial. 如果您尝试做的只是部分应用一个函数,使用partial而不是将包装函数定义为 alambda可以更清晰。
Unfortunately, in this case, the function is hidden inside an operator, and the function operator.modthat exposes it doesn't take keyword arguments, so you can't usefully partial its second operand. So, this is a bad solution in this case. If you really wanted to, you could just write a wrapper that behaves better and partialthat:
不幸的是,在这种情况下,该函数隐藏在运算符中,并且operator.mod公开它的函数不接受关键字参数,因此您不能有效地对其第二个操作数进行分部。因此,在这种情况下,这是一个糟糕的解决方案。如果你真的想,你可以写一个表现更好的包装器,并且partial:
def opmod(a, b):
return a % b
partial(operator.mod, b=i)
In this case, I think you're better off with the other solutions; just keep this one in your head for cases where it isappropriate.
在这种情况下,我认为您最好使用其他解决方案;只要保持这一个在你的头的情况下它是适当的。

