Press "Enter" to skip to content

Python函数调用过程详解

函数调用过程

要说清楚函数调用过程,必须要先知道一个概念“栈”,完整的术语是“the run time stack”,国内教材喜欢叫运行时栈,或者简称栈。run time stack 会存储两类东西

  • call frames 调用帧栈
  • 局部变量的存储

Call frame用来追踪函数的调用过程,当函数被调用时,系统会创建call frame。当函数结束时,销毁call frame。Call frame记录函数名,还有离开的地方,(后面我们用代码行来表示)

代码运行碰到函数调用时,会把frame压到栈顶,当函数结束时,把frame弹出栈,运行指针回到离开的地方

# 请梳理如下代码的几个函数之前的调用过程
def foo():
    print("foo line 1")
    print("foo line 2")
    print("foo line 3")

def fum():
    print("fum line 1")
    print("fum line 2")
    print("fum line 3")

def bar():
    print("bar line 1")
    fum()
    foo()
    print("bar line 4")

go()
调用fum,压栈的过程
出栈,回到13行,以此类推

每次调用函数时,作为frame的一部分,还为返回值分配一些空间。这样当函数返回到你离开的地方时,返回值就像是坐在那等着,拿到返回值后就可以继续执行。

局部变量的作用域

上一节,我们发现,函数调用结束后,会弹出run time stack。因此,我们在函数外部无法访问函数内部的变量

反过来,函数内部如果有一个局部变量,和外部变量同名,是没有影响的。

foo内的var1和外部的var1根本就是两个不同的变量。如果函数内部要直接访问全局变量,需要加上global关键字。(但是不鼓励这种写法)

var1 = "var1 outer"
def foo():
    global va1
    var1 = 'var1 updated in foo'
    print(var1)
foo()
print(var1)

递归函数(additional)

函数内部,可以调用其他函数,也可以调用自身。如果自己调用自己,这个函数就是递归函数。

举个例子,我们来计n! = 1×2×3×…×n,用fact(n)表示,可以看出:

fact(n) = n!= 1×2×3×…×(n-1)×(n) = fact(n-1) ×n

所以,fact(n)可以表示为 fact(n-1) ×n,只有n=1时需要特殊处理。注意,递归函数必须要有递归出口,不能无限制的递归下去。

def fact(n):
    if n == 1:
        return 1
    else:
        return n * fact(n-1)

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注