【问题标题】:Order of frames being pushed on the stack被压入堆栈的帧顺序
【发布时间】:2012-09-26 22:26:39
【问题描述】:

假设您有以下代码。

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 函数?另一种可能是先调用cube函数,然后在解析参数的过程中,必须调用square函数。你能告诉我们什么?这取决于编译器还是语言?

【问题讨论】:

    标签: python compiler-construction stack vm-implementation


    【解决方案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        
    

    【讨论】:

    • 我不知道 dis.dis 这太酷了!谢谢,阿什维尼!
    【解决方案2】:
    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
    

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • C 的行为相似吗?根据文档,这看起来是正确的。我很快就会接受。
      • 是的,根据 C99 规范,“在准备调用函数时,会计算参数,并为每个参数分配相应参数的值。”不能以这种方式工作的语言的一个示例是 Haskell,其中所有内容都是惰性求值的。
      猜你喜欢
      • 2013-10-12
      • 2010-11-28
      • 1970-01-01
      • 2020-12-25
      • 2013-12-26
      • 2013-10-21
      • 2021-05-27
      • 2010-12-23
      相关资源
      最近更新 更多