python 的数组list与元组tuple联系与区别
联系
list与tuple都是存储序列的容器,可以存储各种类型的对象。可以切片与迭代。
区别
list
1. 长度可变
l1=[1,2,3]
print(id(l1))
l1.append(4)
print(id(l1))
结果:
1955078361672
1955078361672
- 元素可修改
l1=[1,2,3]
l1[2]=4
print(l1)
结果:
[1, 2, 4]
- 切片可以复制元素
l1=[1,2,3]
print(l1)
print(id(l1))
l2=l1[:]
print(l2)
print(id(l2))
结果:
[1, 2, 3]
1998405587528
[1, 2, 3]
1998405588040
tuple
- 长度不可变
tp=(1,2,3)
print(tp)
print(id(tp))
tp=tp+(4,)
print(tp)
print(id(tp))
结果:
(1, 2, 3)
1218660839496
(1, 2, 3, 4)
1218659586920
- 元组的元素不可以改变
tp=(1,2,3)
tp[2]=4
结果:
TypeError: 'tuple' object does not support item assignment
3,切片不可复制元组,指向的是同一个元组
tp=(1,2,3)
print(tp)
print(id(tp))
tp2=tp[:]
print(tp2)
print(id(tp2))
结果:
(1, 2, 3)
1998409019544
(1, 2, 3)
1998409019544
性能方面
- 相同元素的数据存储大小
l1=[1,2,3]
tp=(1,2,3)
print(l1.__sizeof__())
print(tp.__sizeof__())
结果:
64
48
list占用的空间大小要比tuple大。列表需要一个间接层(它存储指向元素的指针).这个间接层是一个指针,在64位系统上是64位,因此是8字节。列表还需要空间存储元信息,比如长度。元组可以直接在结构中存储元素,
- list 增加元素的空间分配
但是list最终的大小要看list append使用的情况。
-
初步分配空间:
N个元素,分配N+1的空间 -
当append一个元素时,Python将创建一个足够大的列表,来容纳N个元素和将要被追加的元素。
分配方式:
M = (N >> 3) + (N <9 ? 3 : 6) + 1
重新创建的列表长度大于N+1(虽然我们只触发一次append操作),实际上,为了未来的Append操作,M个元素长度(M>N+1)的内存将会被额外分配,然后,旧列表中的数据被copy到新列表中,旧列表销毁。
额外内存的分配,只会发生在第一次Append操作时,当我们创建普通列表时,不会额外分配内存。 -
当append后分配的空间被沾满时,仍然还有append操作,再次分配空间
l2=[1,2]
print(l2.__sizeof__())
l2.append(3)
for i in range(10):
print(l2)
l2.append(i)
print(l2.__sizeof__())
结果:
56
[1, 2, 3]
88
[1, 2, 3, 0]
88
[1, 2, 3, 0, 1]
88
[1, 2, 3, 0, 1, 2]
120
[1, 2, 3, 0, 1, 2, 3]
120
[1, 2, 3, 0, 1, 2, 3, 4]
120
[1, 2, 3, 0, 1, 2, 3, 4, 5]
120
[1, 2, 3, 0, 1, 2, 3, 4, 5, 6]
184
[1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7]
184
[1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8]
184
3,tuple 还有暂缓保留内存空间的现象
当一个tuple要被垃圾回收机制回收时候,不会立即回收,而是暂缓保留在内存中,等到下次再申请tuple空间时,不会向OS系统申请空间,再直接使用该空间。一次创建tuple速度上也要快,没有频繁的向系统申请空间操作。