用编程语言调用堆栈实现

时间:2015-10-02 06:20:39

标签: python callstack nested-function

我正在上课程编程语言。导师正在解释有关呼叫堆栈的问题。我怀疑导师无法正确解释。如果函数(func1)返回嵌套函数(比如func2并让func2使用func1中定义的变量)。我们将返回的值保存在某个变量中,比如returnFunc。在func1中的return语句完成后,func1将退出。并且func1的堆栈帧应该从调用堆栈中弹出。我们现在在代码中的其他地方调用returnFunc。但是,returnFunc使用fu​​nc1本地的变量,其堆栈帧不再存在于调用堆栈中。这是如何工作的。

示例python代码:

def func1():
    a = 3;
    def func2():
        print(a)
    return func2

returnedFunc = func1()
returnedFunc()

这段代码正确打印3.然而我期待一些垃圾值,因为func1在调用堆栈上不再存在

3 个答案:

答案 0 :(得分:6)

变量&内部函数func1使用的外部函数func2中的值在定义内部函数时与func2“打包”,并且“词法环境”附带{{1}当func2返回时。 func1是所谓的closure(文章顶部给出的示例与您的非常相似,并稍微扩展一下)。当该函数返回时,func2的{​​{1}}副本从堆栈中弹出是正确的,但返回的func1具有a与{{1}的绑定}},将在通过func2调用时使用。 Python比将a绑定到即将成为垃圾的东西更聪明:)

为了说明,让我们使用一个稍微复杂的例子:

3

正如您所料,

returnedFunc()

您可以使用a检查闭包的绑定。请注意,每个闭包都有自己的def outer(x): def inner(y): return x+y return inner inner3 = outer(3) inner5 = outer(5)

副本
>>> inner3(1)
4
>>> inner5(1)
6

但是,如果两个闭包使用相同的非局部变量(如示例中所示),则变量将绑定到同一位置。考虑这种情况(来自OP的评论):

inspect.getclosurevars

调用函数'x'from inspect import getclosurevars >>> getclosurevars(inner3) ClosureVars(nonlocals={'x': 3}, globals={}, builtins={}, unbound=set()) >>> getclosurevars(inner5) ClosureVars(nonlocals={'x': 5}, globals={}, builtins={}, unbound=set()) 表明它们使用def func1(): a = 3 def func2(): nonlocal a a += 1 return a def func3(): nonlocal a a -= 1 return a return func2, func3 f2, f3 = func1() 的相同值:

f2

检查每个的f3属性表明确实如此。 “单元格”(绑定)是相同的,每个“指向”相同的int对象:

a

>>> f2(), f2(), f3(), f3() (4, 5, 4, 3) 个对象(类__closure__)具有>>> f2.__closure__ (<cell at 0x100380fa8: int object at 0x1002739a0>,) >>> f2.__closure__ == f3.__closure__ True 属性;对于cellcellcell_contents是int对象。这是两个单元格指向同一事物的另一个验证:

f2

事实上,这两个细胞是相同的:

f3

答案 1 :(得分:0)

func2仍然包含由编译器分配的scope的副本,因为它使用在该范围内找到的名称。

答案 2 :(得分:0)

Python不同。它有自己的字节码编译器,解释器和堆栈。它不会将C /机器堆栈用于Python代码本身。您的示例也创建了一个新函数。它被分配为堆上的对象,而不是堆栈上的对象。所以它在返回后存在。