闭包如何实现?

闭包如何实现?,第1张

闭包如何实现?

我认为当您将其

i
视为一个 名称 而不是某种 价值 时,会发生什么很明显。你的lambda函数确实像“拍X:查找我的价值,我计算** X”
......所以,当你实际运行的功能,查找
i
只是那么 这样
i
4

您也可以使用当前数字,但必须让Python将其绑定到另一个名称

def makeActions():    def make_lambda( j ):        return lambda x: j * x # the j here is still a name, but now it wont change anymore    acts = []    for i in range(5):        # now you're pushing the current i as a value to another scope and         # bind it there, under a new name        acts.append(make_lambda(i))    return acts

这似乎令人困惑,因为您经常被告知变量和变量的值是同一回事–的确如此,但仅在实际使用变量的语言中。Python没有变量,但是有名称。

关于您的评论,实际上我可以更好地说明这一点:

i = 5 myList = [i, i, i] i = 6print(myList) # myList is still [5, 5, 5].

您说您 将i更改为6
,但这并不是实际发生的情况:

i=6
意思是“我有一个值,
6
我想命名它
i
”。您已经使用
i
过名称的事实对Python而言无关紧要,它只会
重新分配名称 ,而不 更改其值 (仅适用于变量)。

您可以说,在中

myList = [i, i, i]
,无论
i
当前指向的值(数字5)是什么,它都会得到三个新名称:
mylist[0],mylist[1], mylist[2]
。这与调用函数时发生的事情相同:参数被赋予新名称。但这可能违背了有关列表的任何直觉…

这可以在例如解释行为:您分配

mylist[0]=5
mylist[1]=5
mylist[2]=5
-难怪他们不要当你重新分配的变化
i
。如果
i
是可变的东西,例如一个列表,那么更改
i
也将反映在所有条目中
myList
,因为
对于同一个值 您只是拥有 不同的名称

您可以

mylist[0]
=
证明的左手使用的简单事实证明它确实是一个名称。我喜欢叫
=
指定名称 *** 作
:它需要一个名字上的左边,右边一个表达式,然后计算表达式(通话功能,查找值名称后面),直到它有一个值,最后给出了名字价值。它不会 改变任何东西

对于Marks关于编译功能的评论:

好了,引用(和指针)只有在我们有某种可寻址的内存时才有意义。这些值存储在内存中的某个位置,而引用会将您引导到该位置。使用引用意味着转到内存中的该位置并对其进行处理。问题在于这些概念都
没有 被Python使用!

Python VM没有内存的概念-值 在空间中浮动 ,名称是连接到它们的小标签(由一个红色的小字符串表示)。名称和值存在于不同的世界中!

编译函数时,这有很大的不同。如果有引用,则知道所引用对象的存储位置。然后,您可以简单地用该位置替换然后引用。另一方面,名称没有位置,因此(在运行时)您要做的是跟随那个红色小字符串并使用另一端的内容。这就是Python编译函数的方式:在代码中任何有名称的地方,它都会添加一条说明该名称代表什么的指令。

因此,基本上Python确实可以完全编译函数,但是名称是作为嵌套名称空间中的查找而 不是 作为对内存的某种引用进行编译的。

使用名称时,Python编译器将尝试找出其所属的名称空间。这将导致一条指令,从找到的名称空间加载该名称。

这使您回到最初的问题:在中

lambdax:x**i
,将
i
编译为
makeActions
名称空间中的查找(因为
i
在那里使用了它)。Python不知道,也不关心它背后的值(它甚至不必是有效的名称)。代码运行在
i
原始名称空间中查找的代码,并给出或多或少的期望值。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5667001.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存