0. 关键点提要
修过C、C++并详细了解C、C++的函数参数传递中的栈帧的变化(参数怎么入栈出栈)的读者会很好理解本文的内容 ,本质上函数参数传递就是栈的变化, 下面简要介绍C语言中函数调用的过程
1
2
3
4
5 int add(int a, int b)
{
return a + b;
}
add(1, 2);
参数由右向左进栈
1
2 push 2
push 1call指令导致下一条指定的地址进栈
1 push 下一条指令的地址提升堆栈
1
2
3 push ebp
mov ebp, esp
sub esp, 提升堆栈的大小
0.1 名称绑定与赋值
名称只是对象的别名,不同的名称可以表示同一个对象,同一个对象并没有唯一的名称。
0.2 名称解析、名称解析到值
名称解析到哪个作用域,是函数定义的时候就决定了的;具体的解析到值的过程,则是在语句运行时才进行的
1. 名称绑定 VS 赋值语句
1 | a = 1 |
在上述python语句中就是名称绑定,右侧的表达式的结果一定处在某个内存单元中,将那些内存单元分别起了个名字,方便我们之后使用,其中把a、b、c叫做名称,当我们以后使用这个名称的时候,就是在使用对应内存单元的值。
你可以使用del a 来解除名称a对存储的有1这个数值的内存单元的绑定
赋值语句和名称绑定有区别,它除了用于名称绑定以外,还可以用来修改可变对象如列表(list)和字典(dict)
1 | li = [1, 2, 3, 4] # 名称绑定 |
1 | dic = {"java": 30, "python": 40, "c": 100} # 名称绑定 |
1 | import my_module |
上述完全等同于
1 | my_module = __import__('my_module') |
2. 名称解析到作用域
-
名称解析到哪个作用域,是函数定义的时候就决定了的;
函数中只要存在对某个名称的绑定,不管这个语句执行或者没执行,也会导致作用域解析的变化
1
2
3
4
5a = 100
def func():
if False:
a = 1000
return a # UnboundLocalError a只会解析到本函数作用域内 -
具体的解析到值的过程,则是在语句运行时才进行的
1
2
3
4
5
6
7
8def func():
a = 1
def func2():
return a
a = 2
return func2()
func() # 2
3. 函数参数传参
理解好前文C、C++中的函数参数传参的机制,在此不再赘述。