1.列表和元组的基础

列表和元组都是一个可以放置任意数据类型的有序合集。(在绝大多数编程语言中,集合的数据类型必须一致。不过,对于python的列表和元组来说,并无此要求)

2.列表与元组的区别

1)列表是动态的,长度大小不固定,可以随意的增加、删减或者改变元素。

2)元组是静态的,长度大小固定,无法增加、删减或者改变。

3.列表和元组的基本操作和注意事项

1)首先,和其他语言不同,Python中的列表和元组都支持负数索引,-1表示最后一个元素,-2表示倒数第二个元素,以此类推。

2)列表和元组都支持切边操作

3)列表和元组都可以随意嵌套

4)两者可以通过list()和tuple()函数相互转换:



list((1,2.3))        #[1,2.3]

tuple([1,2,3])       #(1,2,3)



5)列表和元组常用的内置函数:



l = [3,2,3,7,8,1]
l.count(3)
#2; count(item)表示统计列表/元组中item出现的次数。
l.index(7)
#3; index(item)表示返回列表/元组中item第一次出现的索引
l.reverse()
#[1,8,7,3,2,3]; list.resverse()表示原地倒转列表
l.sort()
#[1,2,3,3,7,8]; list.sort()表示列表排序(注意元组没有内置这两个函数)



列表和元组存储方式的差异



l = [1,2,3]
print(l.__sizeof__())
#64

tup = (1,2,3)
print(tup.__sizeof__())
#48



对列表和元组,我们放置了相同的元素,但是元素的存储空间,却比列表要少16字节。

由于列表是动态的,所以它需要存储指针,来指向对应的元素(上述例子中,对于int型,8字节)。另外,由于列表可变,所以需要额外存储已经分配的长度大小(8字节),这样才可以实时追踪列表空间的使用情况。当空间不足时,及时分配额外空间。



l = []
l.__sizeof__() // 空列表的存储空间为 40 字节
40
l.append(1)
l.__sizeof__() 
72 // 加入了元素 1 之后,列表为其分配了可以存储 4 个元素的空间 (72 - 40)/8 = 4
l.append(2) 
l.__sizeof__()
72 // 由于之前分配了空间,所以加入元素 2,列表空间不变
l.append(3)
l.__sizeof__() 
72 // 同上
l.append(4)
l.__sizeof__() 
72 // 同上
l.append(5)
l.__sizeof__() 
104 // 加入元素 5 之后,列表的空间不足,所以又额外分配了可以存储 4 个元素的空间



上面的例子,大概描述了列表空间分配的过程。我们可以看到,为了减少每次增加/删除操作时空间分配的开销,Python每次分配空间时都会额外多分配一些,这样的机制(over—allocating)保证了其操作的高效性:增加/删除的时间复杂度均为O(1)。

但是对于元组,情况就不同了。元组长度大小固定,元素不可变,所以存储空间固定。

列表和元组的性能

通过学习列表和元组存储方式的差异,我们可以得出结论:元组要比列表更加轻量级一些,所以总体上来说,元组的性能速度要略优于列表。

另外,Python会在后台,对静态数据做一些资源缓存(resource caching)。通常来说,因为垃圾回收机制的存在,如果一些变量不被使用,Python就会回收它们所占用的内存,返还给操作系统,以便其他变量或其他应用使用。

但是对于一些静态变量,比如元组,如果它不被使用并且占用空间不大时,Python会暂时缓存这部分内存。这样,下次我们在创建同样大小的元组时,Python就可以不用再向操作系统发出请求,去寻找内存,而是可以直接分配之前缓存的内存空间,这样就能大大加快程序的运行速度。