为了去野外烧烤,你创建了一堆的任务清单 - 一叠便条。对一叠便条会有如下操作:插入的待办事项放在清单的最前面;读取待办事项时,只读取最上面的,并将其删除。一叠便条就是栈,插入对应着栈的压入操作,读取并删除对应着栈的弹出操作。
计算机在内部使用被称为调用栈的栈。下面以一段代码来解释调用栈。
def greet(name):
print("hello," + name + "!")
greet2(name)
print("getting ready to say bye...")
bye()
def greet2(name):
print("how are you," + "?")
def bye():
print("ok,bye!")
假设调用 greet(caoqi)
,计算机会首先为这个函数调用分配出一块内存。每当调用函数的时候,计算机都会将函数调用涉及到的所有变量的值存储到内存中。比如一开始name
变量被设置为caoqi
的时候,会将其存储在分配出的内存中。
程序接下来是打印hello,caoqi!
,然后再调用greet2(caoqi)
。同样的,计算机也会为其分配出内存。
计算机使用一个栈来表示这些内存块,其中第二个内存块位于第一个内存块上方。当打印完how are you,caoqi?
,会从函数调用返回,所以,此时栈顶的内存块会被弹出,即函数greet2
被弹出。
弹出之后,栈顶的内存块变为函数greet
,这意味着又回到了函数greet
。调用函数greet2
的时候,只是执行了函数greet
的一部分。这里涉及到一个重要的概念:调用另一个函数的时候,当前的函数暂停并处于未完成状态。执行完函数greet2
后,回到函数greet
,并从离开的地方继续往下运行。首先打印getting ready to say bye...
,再调用函数bye
。
此时,在栈顶增加了函数bye
的内存块。打印完ok,bye!
,从这个函数返回后,函数bye
的栈顶被弹出。最后,又回到了函数greet
,程序已执行完,就从函数greet
返回。
上面提到的用来存储多个函数的变量的栈,被称为调用栈。从上面过程中,也能发现调用栈的缺点,即当调用的函数越多时,调用栈可能会很长,这将占用计算机大量的内存。