zoukankan      html  css  js  c++  java
  • 列表和元组

    差异

    共同点

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

    区别

    列表是动态的,长度大小不固定,可以随意增删改。
    元组是静态的,长度大小固定,无法增删改。

    列表元组存储方式的差异

    先看一个例子

    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)。

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

    看了前面的分析,你也许会觉得,这样的差异可以忽略不计。但是想象一下,如果列表和元组存储元素的个数是一亿,十亿甚至更大数量级时,你还能忽略这样的差异吗?

    列表和元组的性能

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

    另外,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
    

    当然,如果你想要增加、删减或者改变元素,那么列表显然更优。原因你现在肯定知道了,那就是对于元组,你必须得通过新建一个元组来完成。

    列表和元组的使用场景

    那么列表和元组到底用哪一个呢?根据上面所说的特性,我们具体情况具体分析。

    1. 如果存储的数据和数量不变,比如你有一个函数,需要返回的是一个地点的经纬度,然后直接传给前端渲染,那么肯定选用元组更合适。
    def get_location():
        ..... 
        return (longitude, latitude)
    
    1. 如果存储的数据或数量是可变的,比如社交平台上的一个日志功能,是统计一个用户在一周之内看了哪些用户的帖子,那么则用列表更合适。
    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

  • 相关阅读:
    hdu 4521 小明系列问题——小明序列(线段树 or DP)
    hdu 1115 Lifting the Stone
    hdu 5476 Explore Track of Point(2015上海网络赛)
    Codeforces 527C Glass Carving
    hdu 4414 Finding crosses
    LA 5135 Mining Your Own Business
    uva 11324 The Largest Clique
    hdu 4288 Coder
    PowerShell随笔3 ---别名
    PowerShell随笔2---初始命令
  • 原文地址:https://www.cnblogs.com/wuyongqiang/p/10895066.html
Copyright © 2011-2022 走看看