Python 推送到堆栈上的帧的顺序
假设您有以下代码Python 推送到堆栈上的帧的顺序,python,compiler-construction,stack,vm-implementation,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} -
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返回之前
x------>5
就在立方体返回之前
x------>25
立方体(正方形(5))=15625
就在主回归之前
__内置-->
__缓存的----------------->无
__文件------------>无
__文件-->exampleOne.py
__名称----------------->\u主__
__软件包----------------->无
多维数据集------->
广场------->
x------>5
我们感到困惑。square函数是否首先被推到堆栈上,并计算其返回值并传递给cube函数?另一种可能性是首先调用立方体函数,然后在解析参数的过程中,必须调用平方函数。你能告诉我们什么?这取决于编译器或语言吗?当然,它可能取决于语言,但您的示例是Python 在Python中,函数参数总是在调用作为参数的函数之前进行求值。(请参阅。)由于
square(x)
作为cube
的参数传递,因此首先调用square
,然后将结果传递给cube
。换句话说,表达式中的函数调用总是“由内而外”求值,最里面的函数调用首先求值。这就像数学表达式的求值顺序一样(最里面的括号在前)
参数在传递之前进行求值。也许可以这样写,使事情以另一种方式发生,但我不知道有哪种语言能做到这一点,因为它看起来非常不直观。最里面的总是先求值,也就是说,它是最后一个放在堆栈上的 看看这个例子:
>>> 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加载常数1(<0xb76aa770处的代码对象func1,文件“pyshell”19,第2行>)
3生成函数0
6存储快速0(功能1)
4 9加载常数2(<0x8a10530处的代码对象func2,文件“pyshell”19,第4行>)
12生成函数0
15门店快速1(功能2)
6 18加载常量3(<0x8a102f0处的代码对象func3,文件“pyshell”19,第6行>)
21生成函数0
24商店快速2(功能3)
8 27加载快2(func3)#func3放置在堆栈上
30 LOAD_FAST 1(func2)#func2放置在堆栈上
33加载快0(func1)#最后是func1得到
#堆放
36调用函数0
39调用函数1
42调用函数1
45 POP_TOP#删除堆栈顶部项目。
46负载常数0(无)
49返回值
C的行为类似吗?根据文档,这看起来是正确的。我很快就会接受。是的,根据C99规范,“在准备调用函数时,对参数进行求值,并为每个参数分配相应参数的值。”Haskell就是一个不以这种方式工作的语言示例,我不知道dis。dis Dat太酷了!谢谢你,阿什维尼!
>>> 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(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