纯粹的python

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 1
  • call指令导致下一条指定的地址进栈

    1
    push 下一条指令的地址
  • 提升堆栈

    1
    2
    3
    push ebp
    mov ebp, esp
    sub esp, 提升堆栈的大小

0.1 名称绑定与赋值

名称只是对象的别名,不同的名称可以表示同一个对象,同一个对象并没有唯一的名称。

0.2 名称解析、名称解析到值

名称解析到哪个作用域,是函数定义的时候就决定了的;具体的解析到值的过程,则是在语句运行时才进行的

1. 名称绑定 VS 赋值语句

1
2
3
a = 1      
b = 'abcd'
c = (a, b)

在上述python语句中就是名称绑定,右侧的表达式的结果一定处在某个内存单元中,将那些内存单元分别起了个名字,方便我们之后使用,其中把a、b、c叫做名称,当我们以后使用这个名称的时候,就是在使用对应内存单元的值。

你可以使用del a 来解除名称a对存储的有1这个数值的内存单元的绑定


赋值语句和名称绑定有区别,它除了用于名称绑定以外,还可以用来修改可变对象如列表(list)和字典(dict)

1
2
3
4
li = [1, 2, 3, 4]   # 名称绑定
li_a = li # 名称绑定
li_a[0] = 100 # 赋值语句
print(li[0]) # 打印出100

1
2
3
4
dic = {"java": 30, "python": 40, "c": 100}  # 名称绑定
dic_a = dic # 名称绑定
dic_a["java"] = 3000 # 赋值语句
print(dic["java"]) # 打印出3000

1
2
3
4
import my_module
import my_module as m1
from my_module import my_object
from my_module import my_object as o1

上述完全等同于

1
2
3
4
5
6
7
8
9
10
11
my_module = __import__('my_module')

m1 = __import__('my_module')

_ = __import__('my_module')
my_object = _.my_object
del _

_ = __import__('my_module')
o1 = _.my_object
del _

2. 名称解析到作用域

  • 名称解析到哪个作用域,是函数定义的时候就决定了的;

    函数中只要存在对某个名称的绑定,不管这个语句执行或者没执行,也会导致作用域解析的变化

    1
    2
    3
    4
    5
    a = 100
    def func():
    if False:
    a = 1000
    return a # UnboundLocalError a只会解析到本函数作用域内
  • 具体的解析到值的过程,则是在语句运行时才进行的

    1
    2
    3
    4
    5
    6
    7
    8
    def func():
    a = 1
    def func2():
    return a
    a = 2
    return func2()

    func() # 2

3. 函数参数传参

理解好前文C、C++中的函数参数传参的机制,在此不再赘述。

文章作者: 小王同学
文章链接: https://morvan.top/2021/05/25/纯粹的python/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 小王同学的精神驿站