Python 可变类型与不可变类型的内存引用机制详解
本文深入解析Python中可变与不可变数据类型的内存管理机制。通过id()函数查看内存地址,阐明变量赋值、函数传参及列表字典修改时的引用行为。重点对比整型、字符串等不可变类型与列表、字典等可变类型在值改变时内存地址的变化差异,揭示引用计数与对象创建的底层逻辑。
Python变量内存地址与ID函数基础
在Python中,一旦定义了数据,系统便会在内存中开辟一块空间来存储该变量的值,这块已分配的内存空间拥有唯一的内存地址。访问这块内存需要借助变量名,变量名实际上存储的是指向该内存地址的引用,但使用print()函数输出时,显示的是这块内存中实际存储的地址值。这属于Python的设计规范,无需过度纠结其实现细节。
若要获取变量在内存中的具体地址,可以使用内置的id()函数。
常规使用场景如下。
基本数据类型的变量赋值与引用
变量之间的赋值操作,本质上是将一个变量的内存地址传递给另一个变量。这样,两个变量便都指向内存中的同一块空间,因此这两个变量的值是相等的。
a = 1
b = a
print("a:%d b:%d" % (a,b))
print(id(a))
print(id(b))
结果:
a:1 b:1
1711072016
此时,如果有第三个变量c的值与a相等,那么c的地址与a的地址也是一样的。这一点需要牢记。
a = 1
c = 1
print("a:%d c:%d" % (a,c))
print(id(a))
print(id(c))
结果:
a:1 c:1
1711072016
若此时修改变量c的值,Python会在内存中新开辟一块空间来存储这个新值,并将这块新内存的地址赋值给c。
a = 1
c = 1
c = 2
print("a:%d c:%d" % (a,c))
print(id(a))
print(id(c))
结果:
a:1 c:2
1711072032
基本数据类型作为函数参数的传递机制
接下来探讨基本数据类型作为函数参数的情况。
基本数据类型作为函数实参传递时,遵循同样的引用逻辑。
a = 1
print(id(a))
def func(x):
print(id(x))
x = 2
print(id(x))
func(a)
结果:
1711072016
高级数据类型的引用与修改行为
对于列表、字典等高级数据类型的引用机制,情况有所不同。
列表和字典等高级数据类型的变量名同样存储变量的实际地址。当一个列表名赋值给另一个变量时,这两个变量便指向内存中的同一块地址。
list1 = [1,2,3]
list2 = list1
print(list1,list2)
print(id(list1),id(list2))
结果:
[1, 2, 3] [1, 2, 3]
57931896
需要注意的是,高级数据类型每次加载进内存时,其内存地址可能与上一次不同。
若此时修改list2的值,会影响list1的值,但两个变量在内存中的地址保持不变。这一点与基本数据类型的行为不同。
list1 = [1,2,3]
list2 = list1
print(list1,list2)
print(id(list1),id(list2))
list2.append(4)
print(list1,list2)
print(id(list1),id(list2))
结果:
[1, 2, 3] [1, 2, 3]
43841656
[1, 2, 3, 4] [1, 2, 3, 4]
43841656
若此时有第三个列表list3的值也是[1,2,3,4],可以推测list3的地址与list1的地址应该是一样的,但事实并非如此。如果有第三个列表list3的值也是[1,2,3,4],相当于在内存中新开辟一块内存来存储这个值。
list1 = [1,2,3]
list2 = list1
list3 = [1,2,3]
print(list1,list2,list3)
print(id(list1),id(list2),id(list3))
结果:
[1, 2, 3] [1, 2, 3] [1, 2, 3]
16775288 16776768
可变与不可变数据类型的核心区别
最后总结可变数据类型与不可变数据类型的核心区别。
在Python中,哪些是可变数据类型,哪些是不可变数据类型?可变数据类型包括列表list和字典dict;不可变数据类型包括整型int、浮点型float、字符串型string和元组tuple。
用一句话来概括上述过程就是:“Python中的不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象;可变数据类型,允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。”
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









