列表和元组之间有什么区别?


1019

有什么不同?

元组/列表的优点/缺点是什么?


13
其他人在下面回答,但我想指出的是,恕我直言,python具有完全不直观的数据类型名称。我认为其他语言都没有元组(以该名称命名),更糟糕的是,我什至无法将其翻译成我的语言。有谁知道“元组”来自哪里?荷兰语?
Rook

98
元组是数学的基本术语,源自拉丁语(请参阅维基百科)。
nikow

128
对->三元组->四元组->五元组->六元组->嗯,这叫什么,啊草皮,7元组-> 8元组-> ...因此有“ tuple”作为通用名称。
John Fouhy

31
@JohnFouhy已经过了六年,但是:...七人组,八人组,九元组,十元组,十元组,十二元组...:D
Augusta

18
@MegaWidget我以为我们已经确定非元组是list。; D
Augusta

Answers:


1017

除了元组是不可变的之外,还有语义上的区别应指导它们的使用。元组是异构数据结构(即,它们的条目具有不同的含义),而列表是同类序列。元组具有结构,列表具有顺序。

使用这种区别可以使代码更加明确和易于理解。

一个示例是成对的页和行号,以成对参考书中的位置,例如:

my_location = (42, 11)  # page number, line number

然后,您可以将其用作字典中的键来存储有关位置的注释。另一方面,列表可用于存储多个位置。自然地,人们可能想在列表中添加或删除位置,因此列表是可变的很有意义。另一方面,从现有位置添加或删除项目没有意义-因此,元组是不可变的。

在某些情况下,您可能想更改现有位置元组中的项目,例如在页面的各行中进行迭代时。但是元组不变性迫使您为每个新值创建一个新的位置元组。从表面上看,这似乎很不方便,但是使用这样的不可变数据是值类型和函数编程技术的基石,可以具有很多优点。

关于此问题,有一些有趣的文章,例如“ Python元组不仅仅是常量列表”“了解Python中的元组与列表”。官方Python文档也提到了这一点

“组是不可变的,并且通常包含一个异类序列...”。

在像Haskell这样的静态类型语言中,元组中的值通常具有不同的类型,并且元组的长度必须固定。在列表中,所有值都具有相同的类型,并且长度不是固定的。因此区别非常明显。

最后,在Python中有一个namedtuple,这很有意义,因为一个元组已经被认为具有结构。这强调了元组是类和实例的轻量级替代方案的思想。


11
+1,特别是您的第二个链接。喜欢这句话:“此元组用作轻量级记录或结构。”
巴尔的摩

105
“列表是同质序列”-我是Python的新手,但是列表不是异构的吗?来自docs.python.org/py3k/tutorial/introduction.html:“列表项不必全部具有相同的类型。” 但是也许您在谈论的是正式概念,而不是Python。
马修·康奈尔 Matthew Cornell)2012年

13
“元组”的一个好的语义同义词可能是“记录”。它是按特定顺序收集的相关数据项。实际上,我觉得这样collections.namedtuple更好collections.record。例如,在客户记录中交换姓名和地址是没有意义的。实际上,这样做通常是一个错误,元组的不变性阻止您提交。
kindall

4
@nikow:关于What would you do with such a list?,当ppl以缺乏幻想为理由时,我总是不寒而栗。使用混合类型列表非常有用,例如对于某些分层数据结构而言,其中每个列表都由子列表和值元素组成。
塞巴斯蒂安·马赫2014年

18
说元组是异构的并且列表是同质的,是否具有误导性?例如,列表可以包含不同数据类型的混合,即l = [1、2,'a']。我不明白你在说什么。
Celeritas

362

列表和元组之间的区别

  1. 文字

    someTuple = (1,2)
    someList  = [1,2] 
  2. 尺寸

    a = tuple(range(1000))
    b = list(range(1000))
    
    a.__sizeof__() # 8024
    b.__sizeof__() # 9088

    由于元组操作的大小较小,因此它变得更快一些,但是在您拥有大量元素之前,不必多说。

  3. 允许的操作

    b    = [1,2]   
    b[0] = 3       # [3, 2]
    
    a    = (1,2)
    a[0] = 3       # Error

    这也意味着您不能删除元素或对元组进行排序。但是,您可以在列表和元组中都添加一个新元素,唯一的区别是,由于元组是不可变的,因此您并不是真正在添加元素,而是要创建一个新的元组,因此id将会改变

    a     = (1,2)
    b     = [1,2]  
    
    id(a)          # 140230916716520
    id(b)          # 748527696
    
    a   += (3,)    # (1, 2, 3)
    b   += [3]     # [1, 2, 3]
    
    id(a)          # 140230916878160
    id(b)          # 748527696
  4. 用法

    由于列表是可变的,因此不能用作字典中的键,而可以使用元组。

    a    = (1,2)
    b    = [1,2] 
    
    c = {a: 1}     # OK
    c = {b: 1}     # Error

那么,当我尝试将列表大小调整为较大的值时会发生什么?它会更改内存地址(我相信应该更改id)。还是会抛出一个错误?
WanderingMind 2015年

17
@WanderingMind:存储列表值的内存地址与存储列表对象本身的内存地址不同。
汤姆

2
嗯... 除了下面的第一个方框,本文中的所有代码首先3. Permitted operation显示元组大小写。我知道通常会先显示成功,然后显示错误,但这使我的头有些混乱。
dmckee ---前主持人小猫

1
如第3点所示,单个元素列表可以是one_item_list = [a],但是one_tuple = (a,)是对应的元组。注意变量名后的逗号。还要注意two_tuple = (a, b)。这使我不止一次离开(仍然在Python 3中存在)。
mjkrause

1
@Cheng因为对元组进行排序会使其变异,即更改其项目。元组不支持这一点。在python中获取排序后的元组的最简单方法是tuple(sorted(the_unsorted_tuple))
ApproachingDarknessFish

204

如果您去散散步,您可以随时在 (x,y)元组中。

如果要记录您的旅程,可以每隔几秒钟将您的位置附加到一个列表中。

但您无法做到这一点。


37
该示例看起来仅是一个约定。人们可能会争辩说“如果我愿意,我仍然可以使用[x,y]来标​​注坐标”。因此,除非另有一句话,否则该答案将被视为未完成:“阅读@nikow的帖子,为什么不应该使用列表存储坐标”
RayLuo 2013年

71
@Iceberg,我的回答旨在帮助发展直觉。这并不意味着探索该主题的每一个细微差别。
dan-gph

8
不错的例子+1。它强调了元组元素(此处为坐标)的互补性,这就是不允许修改其中任何一个的原因-因为它更改了整个元组的含义(此处为一个点的位置)。
王浩

77

关键区别在于元组是不可变的。这意味着一旦创建元组,就无法更改其值。

因此,如果您需要更改值,请使用列表。

对元组的好处:

  1. 性能略有改善。
  2. 由于元组是不可变的,因此可以将其用作字典中的键。
  3. 如果您无法更改它,那么其他任何人也不能更改它,也就是说,您无需担心任何API函数等。无需询问即可更改元组。

14
请注意,只有在其所有元素都为时,元组才是不可变。您可能会说所有不可变集合都一样,例如frozenset第三方冻结的dict / tree / etc。类型,但这些都不允许您添加可变元素。(当然,元组只有在其所有元素都可以被哈希的情况下才是可哈希的,这是用通常的EAFP方法处理的,因此d[1, [2]]将引发TypeError: unhashable type: 'list'。)
abarnert 2014年

1
如果元组的所有元素都是不可变的,则只能将其用作字典中的键。看到这里
Will Dereham

31

列表是可变的;元组不是。

来自docs.python.org/2/tutorial/datastructures.html

元组是不可变的,通常包含一个异类元素序列,这些元素可以通过拆包(请参阅本节后面的内容)或索引(甚至在命名元组的情况下通过属性)进行访问。列表是可变的,并且它们的元素通常是同类的,并且可以通过遍历列表来访问。


1
我真的认为您还应该考虑语义含义(请参阅下面的答案)。
nikow

现在看来几乎不值得付出努力,但是感谢大家的注意。
duffymo,2009年

六个月后,这就是您所能贡献的全部吗?我当时给出的答案是因为在我最初的答案和评论之间经过的四个小时内,其他人做出的贡献远远超过了。答案不正确吗?尽管nikow对它进行了改进,但并非如此。那么,链接到底会增加什么呢?
duffymo

4
很高兴看到这里的其他答案具有相同的质量,但是只有一个评论者说“ -1”,这才令人讨厌。还有另一个答案,它的质量只有0.5倍,但只有下投票的0.1倍。
塞巴斯蒂安·马赫

2
@duffymo我认为此答案是此页面上最清晰,最简洁的答案。它指出了元组和列表之间唯一真正重要的区别,并且不会无休止地谈论这种公然错误的均质vs异质hogwash。
antant

20

被提及的差异主要语义:人们期待一个元组和列表来表示不同的信息。但这远远超出了指导原则。有些库实际上根据传递的内容而有所不同。以NumPy为例(从我要求更多示例的另一篇文章中复制):

>>> import numpy as np
>>> a = np.arange(9).reshape(3,3)
>>> a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> idx = (1,1)
>>> a[idx]
4
>>> idx = [1,1]
>>> a[idx]
array([[3, 4, 5],
       [3, 4, 5]])

关键是,虽然NumPy可能不是标准库的一部分,但它是一个主要的 Python库,在NumPy列表和元组中是完全不同的东西。


2
这实际上不是一个有用的答案。不同之处在于type(a_list) != type(a_tuple),因此分支所基于的任何库代码的type(x)行为都将有所不同
Eric

1
好一点,我已经编辑了这篇文章:这实际上只是指出语义准则已硬编码到某些库中。

1
使用stdlib / builtins中的示例可能比第三方库中的示例更好。您可以在许多地方使用单个值或值的元组,并且列表或其他序列被视为单个值。例如,'%d %d' % [2, 3]是a TypeError,因为您正尝试将列表传递给第一个%d,而不要将任何值传递给第二个%d。(但是,也有一些反例,例如max…)
abarnert 2014年

有趣的是,我不知道python标准库中有此示例。您说了几个地方?
2014年

18

列表用于循环,元组用于结构,即"%s %s" %tuple

列表通常是同质的,元组通常是异类的。

列表用于可变长度,元组用于固定长度。


16

这是Python列表的示例:

my_list = [0,1,2,3,4]
top_rock_list = ["Bohemian Rhapsody","Kashmir","Sweet Emotion", "Fortunate Son"]

这是Python元组的示例:

my_tuple = (a,b,c,d,e)
celebrity_tuple = ("John", "Wayne", 90210, "Actor", "Male", "Dead")

Python列表和元组的相似之处在于它们都是值的有序集合。除了使用括号“ [...,...]”创建列表的浅层差异以及使用括号“(...,...)”创建的元组之外,它们之间的核心技术“用Python语法进行硬编码”之间的差异是特定元组的元素是不可变的,而列表是可变的(...因此,只有元组是可哈希的,并且可以用作字典/哈希键!)。这就导致了它们的使用方式或不使用方式的差异(通过语法先验地实现)以及人们选择使用它们的方式上的差异(鼓励作为“最佳实践”,后验,这就是智能程序员所做的事情)。 人们赋予元素顺序。

对于元组,“顺序”仅表示存储信息的特定“结构”。在第一个字段中找到的值可以很容易地切换到第二个字段,因为每个值都提供跨两个不同维度或比例的值。它们为不同类型的问题提供答案,并且通常采用以下形式:对于给定的对象/对象,其属性是什么?对象/对象保持不变,属性不同。

对于列表,“顺序”表示顺序或方向。第二个元素必须位于第一个元素之后,因为它基于特定且通用的比例或维度位于第二位。这些元素是一个整体,并且通常针对一个给定属性的形式单个问题提供答案,对于给定的属性,这些对象/对象如何比较?属性保持不变,对象/主题不同。

有无数流行文化的人和不符合这些差异的程序员的例子,有无数人可能在主菜上使用色叉。一天结束后,一切都很好,通常都可以完成工作。

总结一些更好的细节

相似之处:

  1. 重复项 -元组和列表都允许重复项
  2. 索引,选择和切片 -元组和列表都使用括号内的整数值进行索引。因此,如果要给定列表或元组的前三个值,语法将是相同的:

    >>> my_list[0:3]
    [0,1,2]
    >>> my_tuple[0:3]
    [a,b,c]
  3. 比较和排序 -两个元组或两个列表都通过它们的第一个元素进行比较,如果有平局,则通过第二个元素进行比较,依此类推。在较早的元素显示出不同之后,不再关注后续元素。

    >>> [0,2,0,0,0,0]>[0,0,0,0,0,500]
    True
    >>> (0,2,0,0,0,0)>(0,0,0,0,0,500)
    True

区别: -先验,根据定义

  1. 语法 -列表使用[],元组使用()

  2. 可变性 -给定列表中的元素是可变的,给定元组中的元素不是可变的。

    # Lists are mutable:
    >>> top_rock_list
    ['Bohemian Rhapsody', 'Kashmir', 'Sweet Emotion', 'Fortunate Son']
    >>> top_rock_list[1]
    'Kashmir'
    >>> top_rock_list[1] = "Stairway to Heaven"
    >>> top_rock_list
    ['Bohemian Rhapsody', 'Stairway to Heaven', 'Sweet Emotion', 'Fortunate Son']
    
    # Tuples are NOT mutable:       
    >>> celebrity_tuple
    ('John', 'Wayne', 90210, 'Actor', 'Male', 'Dead')
    >>> celebrity_tuple[5]
    'Dead'
    >>> celebrity_tuple[5]="Alive"
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment
  3. 哈希表(字典) -由于哈希表(字典)要求其键是可哈希的,因此是不可变的,因此只有元组可以用作字典键,而不能用作列表。

    #Lists CAN'T act as keys for hashtables(dictionaries)
    >>> my_dict = {[a,b,c]:"some value"}
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'list'
    
    #Tuples CAN act as keys for hashtables(dictionaries)
    >>> my_dict = {("John","Wayne"): 90210}
    >>> my_dict
    {('John', 'Wayne'): 90210}

差异-后验用法

  1. 元素的均质性与异质性-通常,列表对象是同质的,而元组对象是异质的。也就是说,列表用于相同类型的对象/对象(例如所有总统候选人,所有歌曲或所有跑步者),而虽然不是强制的,但元组更多地用于异构对象。

  2. 循环与结构-尽管两者都允许循环(对于my_list中的x,...),但实际上对于列表而言才有意义。元组更适合于结构化和呈现信息(驻留在%s中的%s%s是%s,当前是%s%(“ John”,“ Wayne”,90210,“ Actor”,“ Dead”))


我喜欢哈希表/可哈希示例来解释不可变性的原因-您可以使用元组(record / struct / coordinate / vector / point)作为dict中的复杂键。
戴夫X

9

list的值可以随时更改,但是元组的值不能更改。

优点和缺点取决于使用。如果您拥有从未更改过的数据,则必须使用元组,否则list是最佳选择。


7

列表和元组之间的区别

元组和列表在Python中似乎都是相似的序列类型。

  1. 文字语法

    我们使用括号()构造元组和方括号[ ]以获取新列表。另外,我们可以使用适当类型的调用来获取所需的结构-元组或列表。

    someTuple = (4,6)
    someList  = [2,6] 
  2. 变异性

    元组是不可变的,而列表是可变的。这是以下几点的基础。

  3. 内存使用情况

    由于可变性,您需要更多的内存用于列表,而更少的内存用于元组。

  4. 延伸

    您可以将新元素添加到元组和列表中,唯一的区别是将更改元组的ID(即,我们将有一个新的对象)。

  5. 散列

    元组可散列,而列表则不可。这意味着您可以将元组用作字典中的键。该列表不能用作字典中的键,而可以使用元组

    tup      = (1,2)
    list_    = [1,2] 
    
    c = {tup   : 1}     # ok
    c = {list_ : 1}     # error
  6. 语义学

    这一点是关于最佳实践的。您应该将元组用作异构数据结构,而列表则是同质序列。


1
我在这里投票赞成对扩展和哈希的明确讨论,而在其他方面非常好的现有答案中,我没有注意到。
dmckee ---前主持人小猫

6

列表旨在为同质序列,而元组为异构数据结构。


26
在这一点上,这个答案没有增加任何讨论,因为还有许多其他更好的答案。
乔纳森·莱因哈特

5

正如人们已经在这里回答的那样tuples,虽然lists可变但可变是不变的,但是使用元组有一个重要方面,我们必须记住

如果中tuple包含一个listdictionary内部,则即使它们tuple本身是不可变的,也可以更改它们。

例如,假设我们有一个元组,其中包含一个列表和一个字典,如下所示

my_tuple = (10,20,30,[40,50],{ 'a' : 10})

我们可以将列表的内容更改为

my_tuple[3][0] = 400
my_tuple[3][1] = 500

这使得新的元组看起来像

(10, 20, 30, [400, 500], {'a': 10})

我们也可以将元组中的字典更改为

my_tuple[4]['a'] = 500

这将使整个元组看起来像

(10, 20, 30, [400, 500], {'a': 500})

这是因为 listdictionary是对象,而这些对象并没有改变,而是其指向的内容。

因此,这些tuple遗物毫无例外地保持不变


如果您解释说“即使元组本身是不可变的,也可以更改这些内容”,那么这篇文章将得到改善是因为这些对象保留了自己的身份(所以元组没有更改,因为它仍然包含相同的对象...)。
dmckee ---前主持人小猫

3

PEP 484 -类型提示说,该类型的元素tuple可以单独输入; 这样你可以说Tuple[str, int, float]; 但是list,随着List键入类可以采取仅一种类型的参数:List[str],这提示了2的差异确实是,前者是异质的,而后者本质上是均匀的。

另外,标准库通常使用元组作为C会返回a的标准函数的返回值struct


3

正如人们已经提到的差异一样,我将写有关元组的原因。

为什么首选元组?

小元组的分配优化

为了减少内存碎片并加快分配速度,Python重用了旧的元组。如果不再需要一个元组,并且元组少于20个,而不是将其永久删除,Python会将其移至空闲列表。

一个空闲列表分为20组,其中每个组代表长度为n的0至20之间的元组列表。每个组最多可以存储2000个元组。第一个(零)组仅包含一个元素,代表一个空的元组。

>>> a = (1,2,3)
>>> id(a)
4427578104
>>> del a
>>> b = (1,2,4)
>>> id(b)
4427578104

在上面的示例中,我们可以看到a和b具有相同的ID。那是因为我们立即占领了一个在空闲列表中的被破坏的元组。

列表分配优化

由于可以修改列表,因此Python不会使用与元组相同的优化。但是,Python列表也有一个空闲列表,但仅用于空对象。如果GC删除或收集了一个空列表,则以后可以重复使用。

>>> a = []
>>> id(a)
4465566792
>>> del a
>>> b = []
>>> id(b)
4465566792

资料来源:https : //rushter.com/blog/python-lists-and-tuples/

为什么元组比列表高效?-> https://stackoverflow.com/a/22140115


2

5.3文档中的方向引文元组和序列

尽管元组看起来类似于列表,但是它们通常用于不同的情况和不同的目的。元组是不可变的,并且通常包含异类元素序列,这些元素可以通过拆包(请参阅本节后面的内容)或索引(甚至在namedtuple的情况下通过属性)进行访问。列表是可变的,并且它们的元素通常是同质的,可以通过迭代列表来访问。


1

首先,它们都是Python中的非标量对象(也称为复合对象)。

  • 元组,元素的有序序列(可以包含任何对象,而不会出现别名问题)
    • 不可变的(元组,整数,浮点数,str)
    • 使用串联+(当然会创建全新的元组)
    • 索引编制
    • 切片
    • 单例(3,) # -> (3)而不是(3) # -> 3
  • 列表(其他语言的数组),值的有序序列
    • 可变的
    • 辛格尔顿 [3]
    • 克隆 new_array = origin_array[:]
    • 列表理解[x**2 for x in range(1,7)]给您 [1,4,9,16,25,36](不可读)

使用列表可能还会导致混淆错误(指向同一对象的两个不同路径)。


0

列表是可变的,元组是不可变的。只要考虑这个例子。

a = ["1", "2", "ra", "sa"]    #list
b = ("1", "2", "ra", "sa")    #tuple

现在更改list和tuple的索引值。

a[2] = 1000
print a     #output : ['1', '2', 1000, 'sa']
b[2] = 1000
print b     #output : TypeError: 'tuple' object does not support item assignment.

因此证明了以下代码对元组无效,因为我们试图更新一个元组,这是不允许的。


-1

列表是可变的,元组是不可变的。可变项和不可变项之间的主要区别是在尝试附加项目时的内存使用情况。

创建变量时,会将一些固定内存分配给该变量。如果是列表,则分配的内存将大于实际使用的内存。例如,如果当前内存分配为100字节,则当您要追加第101个字节时,可能会另外分配100个字节(在这种情况下,总共为200个字节)。

但是,如果您知道不经常添加新元素,则应使用元组。元组精确分配所需的内存大小,从而节省了内存,尤其是在使用大容量内存块时。


2
尽管从技术上讲其中有些是正确的,但这并不是可变类型和不可变类型之间的关键区别。更大的区别是,可变类型可以在构造后进行更改,而不变类型则不能。
Roger Fan

1
这也不是原因。内存和可变性彼此无关。那只是列表的特定实现细节。内存也没有分配给变量,而是分配给了对象。变量只是对这些对象的引用。
Roger Fan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.