Python列表与元组的内存存储机制解析及测试疑问解答
列表与元组的内存存储机制解析
我的观察与疑问
我知道Python列表是可变的,因为它们存储的是对元素的引用而非元素本身——列表变量的地址和元素的地址完全不同,我用这段代码验证了这一点:
输入代码
a_list = [1, 2, 3] print(a_list, type(a_list), id(a_list)) for x in range(len(a_list)): print(x, type(x), id(x))
输出结果
[1, 2, 3] <class 'list'> 140125075225856 0 <class 'int'> 140125345710288 1 <class 'int'> 140125345710320 2 <class 'int'> 140125345710352
之前看到资料说元组存储在单个内存块中,我误以为元组的地址和它的元素地址是相同的。但测试元组时,发现元组变量和元素的地址也完全不同:
输入代码
a_tuple = (1, 2, 3) print(a_tuple, type(a_tuple), id(a_tuple)) for x in range(len(a_tuple)): print(x, type(x), id(x))
输出结果
(1, 2, 3) <class 'tuple'> 140124247434368 0 <class 'int'> 140125345710288 1 <class 'int'> 140125345710320 2 <class 'int'> 140125345710352
显然我误解了列表和元组的内存管理逻辑,下面详细解析两者的存储机制:
核心结论先明确
列表和元组本质上都存储的是元素的引用,而非元素本身。两者的区别不在于是否存引用,而在于底层存储引用的数组是否可修改。
列表的存储细节
列表是动态可扩容数组:
- 列表对象自身有独立的内存地址(
id(a_list)返回的就是这个地址) - 列表内部是一个可以动态调整大小的数组,这个数组里的每个位置存放的是对应元素的内存地址(也就是引用)
- 元素本身的内存位置和列表对象的位置完全分离,所以修改元素(比如
a_list[0] = 4)只是把列表里对应位置的引用换成新元素的地址,列表对象的地址不会变;而添加/删除元素时,会根据需要扩容或收缩内部的数组,甚至重新分配内存块复制旧引用
元组的存储细节
元组是静态固定大小数组:
- 元组对象同样有独立的内存地址(
id(a_tuple)的结果) - 所谓“元组存储在单个内存块”,指的是元组用来存放元素引用的数组是一块连续的内存,而非元素本身和元组存在同一块内存里
- 因为是静态数组,元组创建后大小无法修改,内部存储引用的数组也不会被调整,这就是元组“不可变”的核心原因——你没法改变元组里存储的引用集合,也没法改变元组的长度
补充:测试元素地址的正确方式
你之前的代码打印的是索引x的地址,不是元素的地址。要验证元素的引用,应该直接打印元素的id:
a_list = [1,2,3] print("列表对象地址:", id(a_list)) for elem in a_list: print(f"元素{elem}的地址:", id(elem)) a_tuple = (1,2,3) print("\n元组对象地址:", id(a_tuple)) for elem in a_tuple: print(f"元素{elem}的地址:", id(elem))
运行后会看到:
- 列表/元组对象的地址,和每个元素的地址完全不同
- 列表和元组里的同一个元素(比如整数1)地址相同,这是因为Python对小整数有缓存复用机制
内容的提问来源于stack exchange,提问作者Popsicle
相关产品推荐
相关产品推荐

