帧被推入堆栈的顺序

时间:2012-10-05 18:08:12

标签: python compiler-construction stack vm-implementation

假设您有以下代码。

def square(x):
    print ("Just before square returns")
    for k in dir():
        print ("{0} -------> {1}".format(k, eval(k)))
    return x*x
def cube(x):
    print ("Just before cube returns")
    for k in dir():
        print ("{0} -------> {1}".format(k, eval(k)))
    return x*x*x

x = 5
print ("cube(square({0})) = {1}".format(x, cube(square(x))))
print ("Just before main returns")
for k in dir():
    print ("{0} -------> {1}".format(k, eval(k)))

运行此代码会显示以下内容

Just before square returns
x -------> 5
Just before cube returns
x -------> 25
cube(square(5)) = 15625
Just before main returns
__builtins__ -------> <module 'builtins' (built-in)>
__cached__ -------> None
__doc__ -------> None
__file__ -------> exampleOne.py
__name__ -------> __main__
__package__ -------> None
cube -------> <function cube at 0x1037b78>
square -------> <function square at 0x1037af0>
x -------> 5

我们感到困惑。 square函数是否首先被压入堆栈并计算其返回值并传递给cube函数?另一种可能性是首先调用立方体函数,然后在解析参数的过程中,必须调用平方函数。你能告诉我们什么?这取决于编译器或语言吗?

3 个答案:

答案 0 :(得分:1)

嗯,当然它可以取决于语言,但你的例子是Python。

在Python中,函数参数总是在调用它们作为参数的函数之前进行求值。 (请参阅the documentation。)由于square(x)作为cube的参数传递,因此首先调用square,然后将结果传递给cube。换句话说,表达式中的函数调用总是“由内而外”进行评估,首先评估最里面的函数。这就像数学表达式的评价顺序(最里面的括号)。

答案 1 :(得分:1)

x= 0
def j(i):
     global x
     x+=2
     print (x)

     return i+1

def h(i):
     global x
     print (x)
     return i+1

print h(j(1))  \\prints 2,2,3

在传递之前评估参数。可能有可能写它以便事情以其他方式发生但我不知道任何语言这样做,因为它看起来非常不直观。

答案 2 :(得分:1)

最内层总是先评估,即最后一个被放置在堆栈上。

看一下这个例子:

>>> def func():
        def func1():
            print (1)
        def func2(x):
            print (2)
        def func3(y):
            print (3)
        func3(func2(func1()))


>>> func()
1                         #func1() was called first
2                         #then func2()   
3                         #last is func3() 

使用dis.dis()

>>> dis.dis(func)
  2           0 LOAD_CONST               1 (<code object func1 at 0xb76aa770, file "<pyshell#19>", line 2>)
              3 MAKE_FUNCTION            0
              6 STORE_FAST               0 (func1)

  4           9 LOAD_CONST               2 (<code object func2 at 0x8a10530, file "<pyshell#19>", line 4>)
             12 MAKE_FUNCTION            0
             15 STORE_FAST               1 (func2)

  6          18 LOAD_CONST               3 (<code object func3 at 0x8a102f0, file "<pyshell#19>", line 6>)
             21 MAKE_FUNCTION            0
             24 STORE_FAST               2 (func3)

  8          27 LOAD_FAST                2 (func3)      #func3 is placed on stack
             30 LOAD_FAST                1 (func2)      #func2 gets placed on the stack
             33 LOAD_FAST                0 (func1)      #finally it's func1 that gets
                                                        # placed on stack
             36 CALL_FUNCTION            0
             39 CALL_FUNCTION            1
             42 CALL_FUNCTION            1
             45 POP_TOP                          #Removes the top-of-stack item.
             46 LOAD_CONST               0 (None)
             49 RETURN_VALUE