引用和对象

在Python里面一切都是对象,我们定义一个变量,其实解释器在执行的时候分为了两步,一步是在heap里面创建一个对应的对象,另外一步是创建一个以我们指定的名字命名的引用,该引用指向上一步创建的对象,每个对象有一个引用计数,当计数为0的时候该对象会被当做垃圾回收掉。

注意上面第一步里面的heap非常重要,因为我们都知道在C/C++里面创建的变量是存放在stack里面的,函数一旦运行完成临时变量就会被释放掉,但是在python里面对象是否会被释放是依据对象的引用计数是否为0,这会造成和C/C++很多的不同,我们来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
def change_list(arg):
# 在这里面改变list的元素值
arg[3]=5
def new_list(arg):
# 在该函数里面我们往dict里面新增元素,看看会不会被释放
arg['new']=[1,2,3,4]
l=[1,2,3,4]
change_list(l)
d={}
new_list(d)
print("a:",l)
print("d:",d)

上面的两个函数都是没有返回值的,但是这段代码的运行结果是

1
2
a: [1, 2, 3, 5]
d: {'new': [1, 2, 3, 4]}

change_list函数用来改变输入的list的元素值,这个函数其实还是比较好理解,传入一个引用然后通过引用改变对象的值;但是第二个函数如果从C/C++的角度去看会觉得有问题,所以我们得谨记对象是被存放在heap里面的,而且对象是否被释放是看其引用计数是否为0,在new_list函数里面我们定义了一个list对象,然后在传入的dict参数里面保存了它的一个引用,当函数运行完成后list对象的引用计数不为0,所以不会被释放,所以在函数外面我们可以看到通过变量d可以访问该list对象,在C/C++里面和这个类似的是定义一个变量/对象,然后将其地址赋值给传入的二级指针参数,但是当函数执行完成后我们知道我们定义的变量/对象将不复存在。

变量的赋值

因为Python的变量是指向对象的引用,因此当变量之间赋值的时候就出现了有趣现象。

1
2
3
4
a0=[1,2,3,4]
a1=a0
a1[3]=5
print(a0)

该代码的输出如下:

1
[1, 2, 3, 5]

为什么呢?因为变量的引用属性所致。a1=a0只是让a0a1两个引用指向同一个对象而已,所以对a1指向的对象的操作也就是对a0指向的对象进行操作。