python 的 tuple 是不是冗余设计?

一般来说,tuple 是不可变的(immutable)可以包含多种类型成员的数据结构,list 是可变的包含同类型成员的数据结构。 但是 python…
关注者
665
被浏览
143,794

51 个回答

泻药,这个问题应该等价于『tuple有什么list不可替代的优点』。

tuple这样的设计当然不是『人为的限制』,事实上,这是一种trade off,tuple以放弃对元素的增删为代价必然换取了一些list所没有的优点,是什么优点呢?

是全面优于list的性能

我们来做几个实验

1.创建

In [1]: %timeit [1, 2, 3, 4, 5]
128 ns ± 1.51 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [2]: %timeit (1, 2, 3, 4, 5)
15 ns ± 0.166 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

创建同样大小的list和tuple,可以看到list的时间开销几乎是tuple的10倍

@冒泡 指出元素全部为immutable的tuple会作为常量在编译时确定,因此产生了如此显著的速度差异, 因此用用户定义的类作第二次测试

In [34]: class foo:
    ...:     pass
In [35]: %timeit [foo(), foo(), foo()]
444 ns ± 7.29 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [36]: %timeit (foo(), foo(), foo())
363 ns ± 2.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

可以看到tuple仍然快于list,只是并没有如此明显的差异


2. 遍历

In [3]: lst = [i for i in range(0xffff)]
In [4]: tpl = tuple(i for i in range(0xffff))
In [5]: %timeit for each in lst: pass
782 µs ± 15.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [6]: %timeit for each in tpl: pass
760 µs ± 9.38 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

对两个大表进行遍历,tuple与list速度相似(感谢 @采石工 指出疏漏)

3.空间开销

In [8]: from sys import getsizeof
In [9]: getsizeof(lst)
Out[9]: 578936
In [10]: getsizeof(tpl)
Out[10]: 524328

储存同样元素的list和tuple, list有更多空间开销



另外,tuple还具有一些list没有的特性(也不能算作优点吧),比如因为tuple是 immutable, 所以它是可哈希的(hashable)的。

In [11]: hash(tpl)
Out[11]: 7487529697070271394
In [12]: hash(lst)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)