我只是偶然发现了一个递归lambdas的有趣例子,我真的不明白它为什么以这种方式工作。你知道吗
rec = lambda x : 1 if x==0 else rec(x-1)*x
f = rec
rec = lambda x: x+1
print(f(10))
在javascript中也是如此。你知道吗
var rec = function(a) {
if (a == 0) return 1;
return rec(a - 1) * a;
}
var f = rec
rec = function(a) {
return a + 1;
}
console.log(f(10));
令我惊讶的是,这两张照片都是100张而不是10张!(如我所料)。你知道吗
为什么rec的重新分配会改变f函数的行为?在lambda中捕获rec变量时,它不是指lambda本身吗?你知道吗
编辑。 由于大多数答案解释了发生了什么,让我重新措辞的问题,因为我正在寻找一个更深入的解释。你知道吗
那么在第一行声明函数rec的时候,为什么函数体中的rec没有绑定到它自己呢?你知道吗
例如,如果您使用JavaScript并以一种看似“相同”的方式重写第一行,您将得到以下答案之一: 你知道吗
var rec =function rec(a) {
if (a == 0) return 1;
return rec(a - 1) * a;
};
f = rec;
rec = function (a) {
return a + 1;
}
console.log(f(10));
这张打印出10张!正如人们所料。你知道吗
因此在本例中,“内部rec”(在函数体中)绑定到函数名的rec,而不是查看rec变量,并且变量rec的重新分配并没有改变行为。你知道吗
因此,我真正要问的是,这些语言决定如何绑定lambdas中的变量的机制。你知道吗
我正在为一个类项目编写一个解释器,我遇到了一个相同的问题,即何时何地绑定这些变量。所以我想了解如何在流行语言中实现类似的功能。你知道吗
您可以添加一些
console.log
并查看,首先用10
调用f
,然后用9
调用rec
,结果是10 * 10
。你知道吗var rec = function(a) { console.log('f', a); if (a == 0) return 1; return rec(a - 1) * a; }; f = rec; rec = function(a) { console.log('rec', a); return a + 1; } console.log(f(10));
;保持
rec
。你知道吗我将为python解决这个问题,因为这是我所熟悉的。你知道吗
首先,这种行为是可能的,因为python(我想看起来像javascript)遵循闭包的后期绑定。further read
后期绑定是在运行时查找闭包中的名称(与早期绑定不同,早期绑定是在编译时查找名称)
这允许在运行时改变行为,通过重新绑定运行时正在查找的变量(例如rec之类的函数)。你知道吗
最后一步就是将lambda函数转换成等价的
def
语法,这样真正的行为就更清楚了。你知道吗代码:
可等同于:
首先:
注意,python不会抱怨rec即使在干净的会话/内核上也不存在,因为它在函数定义期间不查找该值。延迟绑定意味着除非调用这个函数,否则python不关心rec是什么。你知道吗
然后:
现在我们更改
rec
函数并观察到
f
的后续函数调用将使用后期绑定rec,即在函数调用上查找的rec。你知道吗注:完整代码添加如下:
这3条语句可以归结为一条语句
从1&2
从上方&;3
相关问题 更多 >
编程相关推荐