词法闭包是如何工作的? [英] How do lexical closures work?

查看:26
本文介绍了词法闭包是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在研究 Javascript 代码中的词法闭包问题时,我在 Python 中遇到了这个问题:

While I was investigating a problem I had with lexical closures in Javascript code, I came along this problem in Python:

flist = []

for i in xrange(3):
    def func(x): return x * i
    flist.append(func)

for f in flist:
    print f(2)

请注意,此示例谨慎地避免了 lambda.它打印4 4 4",这令人惊讶.我期待0 2 4".

Note that this example mindfully avoids lambda. It prints "4 4 4", which is surprising. I'd expect "0 2 4".

这个等效的 Perl 代码做对了:

This equivalent Perl code does it right:

my @flist = ();

foreach my $i (0 .. 2)
{
    push(@flist, sub {$i * $_[0]});
}

foreach my $f (@flist)
{
    print $f->(2), "
";
}

打印0 2 4".

你能解释一下区别吗?

更新:

问题不是 i 是全球性的.这显示了相同的行为:

The problem is not with i being global. This displays the same behavior:

flist = []

def outer():
    for i in xrange(3):
        def inner(x): return x * i
        flist.append(inner)

outer()
#~ print i   # commented because it causes an error

for f in flist:
    print f(2)

如注释行所示,i 在这一点上是未知的.尽管如此,它仍会打印4 4 4".

As the commented line shows, i is unknown at that point. Still, it prints "4 4 4".

推荐答案

Python 实际上按照定义的方式运行.创建了三个独立的函数,但它们每个都有定义它们的环境的闭包 - 在这种情况下,全局环境(或外部函数的环境,如果循环放置在另一个函数中).然而,这正是问题所在——在这种环境中,i 发生了变异,并且所有闭包都引用相同的 i.

Python is actually behaving as defined. Three separate functions are created, but they each have the closure of the environment they're defined in - in this case, the global environment (or the outer function's environment if the loop is placed inside another function). This is exactly the problem, though - in this environment, i is mutated, and the closures all refer to the same i.

这是我能想到的最佳解决方案 - 创建一个函数创建器并调用 那个 代替.这将为创建的每个函数强制不同的环境,每个函数都有一个不同的 i.

Here is the best solution I can come up with - create a function creater and invoke that instead. This will force different environments for each of the functions created, with a different i in each one.

flist = []

for i in xrange(3):
    def funcC(j):
        def func(x): return x * j
        return func
    flist.append(funcC(i))

for f in flist:
    print f(2)

这就是混合副作用和函数式编程时会发生的情况.

This is what happens when you mix side effects and functional programming.

这篇关于词法闭包是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆