我认为当您将其
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原始名称空间中查找的代码,并给出或多或少的期望值。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)