目录前端
列表和元组,都是一个能够放置任意数据类型的有序集合。
在绝大多数语言中,集合的数据类型必须一致。不过对于python中的列表和来讲没有这样的要求python
列表是动态的,长度大小不固定,能够随意增删改。
元组是静态的,长度大小固定,没法增删改。git
先看一个例子github
l = [1, 2, 3] l.__sizeof__() # 64 tup = (1, 2, 3) 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)。app
可是对于元组,状况就不一样了。元组长度大小固定,元素不可变,因此存储空间固定。函数
看了前面的分析,你也许会以为,这样的差别能够忽略不计。可是想象一下,若是列表和元组存储元素的个数是一亿,十亿甚至更大数量级时,你还能忽略这样的差别吗?oop
经过学习列表和元组存储方式的差别,咱们能够得出结论:元组要比列表更加轻量级一些,因此整体上来讲,元组的性能速度要略优于列表。性能
另外,Python 会在后台,对静态数据作一些资源缓存(resource caching)。一般来讲,由于垃圾回收机制的存在,若是一些变量不被使用了,Python 就会回收它们所占用的内存,返还给操做系统,以便其余变量或其余应用使用。
可是对于一些静态变量,好比元组,若是它不被使用而且占用空间不大时,Python 会暂时缓存这部份内存。这样,下次咱们再建立一样大小的元组时,Python 就能够不用再向操做系统发出请求,去寻找内存,而是能够直接分配以前缓存的内存空间,这样就能大大加快程序的运行速度。
下面的例子,是计算初始化一个相同元素的列表和元组分别所需的时间。咱们能够看到,元组的初始化速度,要比列表快 5 倍。
python3 -m timeit 'x=(1,2,3,4,5,6)' 20000000 loops, best of 5: 9.97 nsec per loop python3 -m timeit 'x=[1,2,3,4,5,6]' 5000000 loops, best of 5: 50.1 nsec per loop
但若是是索引操做的话,二者的速度差异很是小,几乎能够忽略不计。
python3 -m timeit -s 'x=[1,2,3,4,5,6]' 'y=x[3]' 10000000 loops, best of 5: 22.2 nsec per loop python3 -m timeit -s 'x=(1,2,3,4,5,6)' 'y=x[3]' 10000000 loops, best of 5: 21.9 nsec per loop
固然,若是你想要增长、删减或者改变元素,那么列表显然更优。缘由你如今确定知道了,那就是对于元组,你必须得经过新建一个元组来完成。
那么列表和元组到底用哪个呢?根据上面所说的特性,咱们具体状况具体分析。
def get_location(): ..... return (longitude, latitude)
viewer_owner_id_list = [] # 里面的每一个元素记录了这个 viewer 一周内看过的全部 owner 的 id records = queryDB(viewer_id) # 索引数据库,拿到某个 viewer 一周内的日志 for record in records: viewer_owner_id_list.append(record.id)
关于列表和元组,咱们今天聊了不少,最后一块儿总结一下你必须掌握的内容。
总的来讲,列表和元组都是有序的,能够存储任意数据类型的集合,区别主要在于下面这两点。
列表是动态的,长度可变,能够随意的增长、删减或改变元素。列表的存储空间略大于元组,性能略逊于元组。
元组是静态的,长度大小固定,不能够对元素进行增长、删减或者改变操做。元组相对于列表更加轻量级,性能稍优。
empty_list = list() # 方式一 empty_list = [] # 方式二 """ 区别主要在于list()是一个函数调用,Python的function call会建立stack, 而且进行一系列参数检查的操做,比较expensive,反观[]是一个内置的C函数, 能够直接被调用,所以效率高。 """
list和tuple的内部实现都是array的形式,list由于可变,因此是一个over-allocate的array,tuple由于不可变,因此长度大小固定。具体能够参照源码
list: https://github.com/python/cpython/blob/master/Objects/listobject.c.
tuple: https://github.com/python/cpython/blob/master/Objects/tupleobject.c