- 变量赋值时的引用传递
- 可变对象和不可变对象
- Python内存分配
变量赋值时的引用传递
在Python语言中,对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。
要保持追踪内存中的对象,Python使用了引用计数这一简单技术。也就是说Python内部记录着所有使用中的对象各有多少引用。一个内部跟踪变量,称为一个引用计数器。每个对象各有多少个引用,简称引用计数。当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,也就是说,这个对象的引用计数变为0时,它被垃圾回收。
当对象被创建并(将其引用)赋值给变量时,该对象的引用计数就被设置为1。当同一个对象(的引用)又被赋值给其他变量时,或作为参数传递给函数、方法或类实例时,或者被赋值为一个窗口对象的成员时,该对象的一个新的引用,或者称作别名,就被创建(则该对象的引用计数自动加1)。
当对象的引用被销毁时,引用计数会减少。最明显的例子就是当引用离开其作用范围时,这种情况最经常出现在函数运行结束时,所有局部变量都被自动销毁,对象的引用计数也就随之减少。当变量被赋值给另外一个对象时,原对象的引用计数也会自动减1。其他造成对象的引用计数减少的方式包括使用
del
语句删除一个变量,或者当一个对象被移出一个窗口对象时(或该容器对象本身的引用计数变成了0时)。
>>> a =
>>> b = a
>>> id(a), id(b)
(, )
>>> a =
>>> a, b
(, )
>>> id(a), id(b)
(, )
在上面的例子中,
a = 1
使变量
a
指向了整型对象
1
,
b = a
使变量
b
也指向了整型对象
1
,通过语句
id(a), id(b)
可以看到变量
a
和变量
b
所指向的内存地址相同。
语句
a = 2
将新的对象
2
赋值给了变量
a
,此时变量
a
指向了对象
2
,变量
b
仍然指向原来的对象
1
。通过语句
id(a), id(b)
可以看到变量
a
与变量
b
所指向的内存地址不同。
可变对象和不可变对象
Python语言中的对象分为可变对象和不可变对象。
- 不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
- 可变对象,该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟出新的地址,通俗点说就是原地改变。
数字、字符串和元组是不可变类型,列表和字典是可变类型。
>>> a =
>>> id(a)
>>> a = a +
>>> a
>>> id(a)
在上面的例子中,语句
a = a + 1
改变变量
a
的值时,由于变量
a
所指向的对象
1
是不可变对象,因而创建了新的对象
2
并使变量
a
指向了对象
2
。
>>> a = (, , )
>>> id(a)
>>> a = a + (, , )
>>> a
(, , , , , )
>>> id(a)
可以看到使用元组的结果与整型对象相同。
>>> a = [, , ]
>>> b = a
>>> id(a), id(b)
(, )
>>> b += [, , ]
>>> a, b
([, , , , , ], [, , , , , ])
>>> id(a), id(b)
(, )
上面是可变对象的一个例子,变量
a
和变量
b
同时指向了列表对象
[1, 2, 3]
,当语句
b += [4, 5, 6]
改变变量
b
的值时,并没有创建新的列表对象,而是直接改变了原先变量
a
和变量
b
所指向的列表对象。
在Python中
a += b
和
a = a + b
是有区别的。
a += b
直接对变量
a
进行操作,会改变变量
a
的值。
a = a + b
中,
a + b
会生成一个新的对象,变量
a
将指向这个新对象。
>>> a = [, , ]
>>> b = a
>>> id(a), id(b)
(, )
>>> b = b + [, , ]
>>> a, b
([, , ], [, , , , , ])
>>> id(a), id(b)
(, )
Python内存分配
Python中会为每个出现的对象分配内存,哪怕他们的值完全相等(注意是相等不是相同)。如执行
a = 2.0
,
b = 2.0
这两个语句时会先后为
2.0
这个
Float
类型对象分配内存,然后将
a
与
b
分别指向这两个对象。所以
a
与
b
指向的不是同一对象:
>>> a =
>>> b =
>>> a is b
False
>>> a == b
True
但是为了提高内存利用效率对于一些简单的对象,如一些数值较小的
int
对象,Python采取重用对象内存的办法,如执行
a = 2
,
b = 2
时,由于
2
作为简单的
int
类型且数值小,Python不会两次为其分配内存,而是只分配一次,然后将
a
与
b
同时指向已分配的对象:
>>> a =
>>> b =
>>> a is b
True
如果赋值的不是
2
而是大的数值,情况就跟前面的一样了:
>>> a =
>>> b =
>>> a is b
False
>>> id(a)
>>> id(b)
两个对象即便值相等,但仍然是不同的对象。
>>> id()
>>> id()
参考文献
[1] Python核心编程(第二版)
[2] https://www.cnblogs.com/sun-haiyu/p/7096918.html
[3] https://blog.csdn.net/weixin_36250487/article/details/79620874