Python中列表和元组有什么区别?

7
哪种更有效率?每种的典型用途是什么?

1
为什么元组比列表快? 请参考:https://dev59.com/gXA75IYBdhLWcg3wW3oZ - mechanical_meat
1
@Adam - 我认为这不是重复,但非常相关。 - user180247
4个回答

7

列表是可变序列,具有许多方法(包括变异和非变异的方法),通常用作通用容器(它们的项可以是任何类型的对象,尽管有时认为列表最好具有相同类型或等效使用的项)。

元组是不可变序列,具有非常少的方法(所有非变异特殊方法),通常在需要不可变性以将容器用作集合中的项或字典中的键时使用(尽管项目也必须是不可变的——例如,字符串,数字或其他嵌套元组才能正常工作)。它们的项可以是任何类型的对象,对于元组来说,具有许多不同且独特类型的项是完全正常的。

有些情况下,元组或列表都可以很好地使用,在这些情况下,元组稍微小一些且构建速度更快的事实可以用于支持选择元组。例如,当函数需要返回多个结果时,最常规的做法是使用元组。

return fee, fie, foo, fum

即,返回一个包含四个相关项目的元组,而不是
return [fee, fie, foo, fum]

即,返回一个包含四个项目的列表——除了(性能方面的小收益),“返回元组”这个常见的习惯用法还解决了多个结果返回的问题,这些结果通常不是相同的,也不能互换,因此从风格上讲,使用列表可能被认为是更加可疑的选择。

tuple 的一个有用变体是它的子类型 collections.namedtuple (需要 Python 2.6 或更高版本),它允许您通过名称(使用属性语法)以及索引(正常方式)访问项目。例如,在模块顶部进行 import collections 后,上述 return 语句可能会变成...

freturn = collections.namedtuple('freturn', 'fee fie foo fum')

def f():
  ...
return freturn(fee, fie, foo, fum)

现在,f()的调用者可以像以前一样使用其返回值作为元组,但会获得更好的选择,例如...

r = f()
print r.fie

取而代之,使用更加清晰易读的内容。
print r[1]

重要的是需要注意,使用collections.namedtuple创建的命名元组子类与直接使用元组相比基本没有额外开销,或者如文档所述,它们“轻量级且不需要比普通元组更多的内存。”

我认为文档可能没有详细说明,对于命名元组的多个实例进行正则化处理时,不会有额外的开销,但是会使用一定量的额外内存,因为您实际上正在动态创建一个新类型(当然具有某些,尽管轻微的内存占用)。 (顺便说一句,我仍然给你点赞,因为你的回答非常详尽)。 - Nathan Ernst

6
一个列表是可变的,你可以向其中添加元素。而元组则不行,这意味着它(稍微)更有效率。元组也是可哈希的,因此可以用作例如字典中的键。
阅读 this

这个链接完全忽略了 set(以及其他不常用的集合,它们基本上是其他集合的变体 - frozenset 是一个不可变的 set,bytes 是一个列表(带有一些语法糖)等等...)。仍然 +1。 - user395760
问题中没有提到set,那么为什么答案中要提到它呢?是的,setfrozensetlisttuple之间有可比较的差异。虽然我使用set的频率远不及listtuple,但它们是我工具箱中不可或缺的工具。 - Nathan Ernst
1
我有点挑剔,但是不可变性并不意味着可哈希性,就像可变性并不意味着某些东西不可哈希一样。例如,用户定义类的实例默认情况下是可哈希的,但这并不意味着它们是不可变的。不可否认的是,一个不可变类型不可哈希是不寻常的,但这确实是可能的。 - Scott Griffiths

3

列表是可变的(可以更改),元组是不可变的。典型用途:听起来有些陈词滥调,但当你需要更改值时使用列表。由于其不可变性,元组通常会更有效率(除非您像使用列表一样频繁复制它们...)


1

在阅读了Python内置类型文档之后,我创建了下面的表格来展示六个可迭代容器之间的主要区别。

<pre>
Container   Notation     Index [n:m]   Mutable   Hashable
=========   ==========   ===========   =======   ========
String      ' ' or " "    position     Immutable    Yes
Range       range(,,)     position     Immutable    Yes
Tuple       (,)           position     Immutable    Yes
List        [,]           position     Yes          No
Set         {,}           No           Yes          No
Dict        {k:v,k:v}     by key       Yes          No
</pre>

搜索集合和字典更快,因为它们是哈希的而不是顺序的,因此与大小无关。元组和列表相同,除了元组是不可变的,方法比列表少,因此不支持项目赋值来更改其内容。但是,可以连接两个元组以实现“追加”功能,即t1 += t2

由于只有不可变序列类型支持hash(),因此列表、集合和字典不能用作字典键。下面很容易看到这一点,其中'a'是一个包含int、float、str、range和tuple等异构不可变键类型的字典序列:

>>> a
{range(2, 5, 2): 'range', 3: 15, 4.5: 16, 'llmjxm': 'c', -555: 666, -4.5: -25, (5, 6, 7): 'blue', 'abc3': 215, (1, 2, 3): 'red'}
>>> for item in a.keys():
...     print(item, '\t\t==>>', a[item])
... 
range(2, 5, 2)      ==>> range
3       ==>> 15
4.5         ==>> 16
llmjxm      ==>> c
-555        ==>> 666
-4.5        ==>> -25
(5, 6, 7)       ==>> blue
abc3        ==>> 215
(1, 2, 3)       ==>> red
>>> 

如果使用可变类型的键,则会导致 TypeError 错误:

>>> a[{5}] = 56
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> a[[5]] = 56
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> a[{5:6}] = 56
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> a[-555] = 666
>>> 

请参考link1link2获取更多细节。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接