ChatGPT解决这个技术问题 Extra ChatGPT

列表和元组有什么区别?

元组/列表之间有什么区别,它们的优点/缺点是什么?

其他人在下面回答,但我想指出,恕我直言,python 有一个完全不直观的数据类型名称。我认为任何其他语言都没有元组(按那个名字),更糟糕的是,我什至无法用我的语言翻译它。有谁知道“元组”来自哪里?荷兰语?
元组是数学中的一个基本术语,源自拉丁语(参见维基百科)。
对 -> 三元组 -> 四元组 -> 五元组 -> 六元组 -> 嗯,它叫什么,啊,草皮,7元组 -> 8元组 -> ...因此“元组”是一个通用名称。
@JohnFouhy 六年多过去了,但是:......七元组,八元组,九元组,十元组,十元组,十二元组......:D
@MegaWidget 我以为我们已经确定非元组是list。 ;D

U
Uvuvwevwevwe

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

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

一个例子是成对的页码和行号来引用书中的位置,例如:

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

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

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

关于这个问题有一些有趣的文章,例如 "Python Tuples are Not Just Constant Lists""Understanding tuples vs. lists in Python"。 Python 官方文档 also mentions this

“元组是不可变的,通常包含异构序列......”。

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

最后是 Python 中的 namedtuple,这是有道理的,因为元组已经应该具有结构。这强调了元组是类和实例的轻量级替代方案。


+1,特别是对于您的第二个链接有一个很好的例子。喜欢这句话:“这个元组用作轻量级记录或结构。”
“列表是同质序列” - 我是 Python 新手,但列表不是异构的吗?来自 docs.python.org/py3k/tutorial/introduction.html :“列表项不必都具有相同的类型。”但也许你是在谈论正式的概念,而不是 Python 承担它。
“元组”的一个好的语义同义词可能是“记录”。它是按特定顺序排列的相关数据项的集合。事实上,我觉得将 collections.namedtuple 称为 collections.record 会更好。例如,交换客户记录中的姓名和地址是没有意义的;事实上,这样做通常会是一个错误,元组的不变性会阻止您提交。
@nikow:关于What would you do with such a list?,当人们使用缺乏幻想作为论据时,我总是发抖。使用混合类型列表非常有效,例如对于某些分层数据结构,其中每个列表都由子列表和值元素组成。
说元组是异构的而列表是同质的不是误导吗?例如,一个列表可以混合不同的数据类型,即 l = [1, 2, 'a']。我不明白你在说什么。
r
rivamarco

列表和元组的区别

字面量 someTuple = (1,2) someList = [1,2] 大小 a = tuple(range(1000)) b = list(range(1000)) a.__sizeof__() # 8024 b.__sizeof__() # 9088 由于元组操作的尺寸越小,它变得越快,但在您拥有大量元素之前,无需提及太多。允许的操作 b = [1,2] b[0] = 3 # [3, 2] a = (1,2) a[0] = 3 # 错误 这也意味着你不能删除一个元素或对 a 进行排序元组。但是,您可以向列表和元组添加一个新元素,唯一的区别是,由于元组是不可变的,因此您并没有真正添加元素,而是创建了一个新元组,因此 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 用法 由于列表是可变的,它不能用作字典中的键,而可以使用元组。 a = (1,2) b = [1,2] c = {a: 1} # OK c = {b: 1} # 错误


那么当我尝试将列表大小调整为较大的值时会发生什么?它会改变内存地址(我认为应该改变id)。或者它会给我一个错误?
@WanderingMind:存储列表值的内存地址与存储列表对象本身的内存地址不同。
嗯......这篇文章中的所有代码除了 3. Permitted operation 下的第一个框首先显示了元组的情况。我知道显示成功然后显示错误是很常见的,但这让我的头脑混乱了片刻。
如第3点所示,单个元素列表可以是one_item_list = [a],但one_tuple = (a,)是对应的元组。注意变量名后面的逗号。但还要注意 two_tuple = (a, b)。这不止一次让我失望(在 Python 3 中仍然存在)。
@Cheng 因为对元组进行排序会使其发生变异,即更改其项目。元组不支持这一点。在 python 中获取排序元组的最简单方法是 tuple(sorted(the_unsorted_tuple))
A
AGN Gazer

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

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

但是你不能反过来做。


这个例子看起来只是一个约定。人们可能会争辩说“如果我愿意,我仍然可以使用 [x, y] 来记录坐标”。因此,这个答案被认为是未完成的,除非再多一句:“阅读@nikow 的帖子,了解为什么不应该使用列表来存储坐标”
@Iceberg,我的回答旨在帮助培养直觉。这并不是要探索该主题的每一个细微差别。
很好的例子+1。它强调元组元素(这里是坐标)的互补性,这就是不允许修改其中任何一个的原因——因为它改变了整个元组的含义(这里是一个点的位置)。
t
tmthyjames

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

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

元组的好处:

性能略有提升。由于元组是不可变的,它可以用作字典中的键。如果你不能改变它,其他人也不能,也就是说你不需要担心任何 API 函数等。在不被询问的情况下改变你的元组。


请注意,元组只有在其所有元素都是时才是不可变的。您可以说所有不可变集合都是如此,例如 frozenset 或各种第三方冻结的 dict/tree/etc。类型,但这些都不允许您添加可变元素。 (当然,一个元组只有在它的所有元素都是可散列的,它以通常的 EAFP 方式处理,所以 d[1, [2]] 将引发 TypeError: unhashable type: 'list'。)
如果一个元组的所有元素都是不可变的,那么元组只能用作字典中的键。请参阅here
d
duffymo

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

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

元组是不可变的,并且通常包含通过解包(参见本节后面部分)或索引(甚至在命名元组的情况下通过属性)访问的异构元素序列。列表是可变的,它们的元素通常是同质的,可以通过遍历列表来访问。


我真的认为您还应该考虑语义含义(请参阅下面的答案)。
现在似乎不值得付出努力,但感谢您的提醒。
@duffymo 我认为这个答案是这个页面上最清晰、最简洁的答案。它指出了元组和列表之间唯一真正重要的区别,并且不会无休止地喋喋不休地谈论这种公然错误的同质与异构的废话。
C
Community

been mentioned 差异主要是语义上的:人们期望元组和列表表示不同的信息。但这不仅仅是指导方针;一些库实际上根据它们传递的内容而表现不同。以 NumPy 为例(从 another post 复制,我要求提供更多示例):

>>> 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 中,列表和元组是完全不同的东西。


这不是一个真正有用的答案。不同之处在于 type(a_list) != type(a_tuple),因此任何基于 type(x) 的库代码分支都会表现不同
好点,我已经编辑了帖子:这实际上只是指出语义指南被硬编码到某些库中。
使用 stdlib/builtins 中的示例可能比使用第三方库中的示例更好。有许多地方可以使用单个值或值的元组,并且列表或其他序列被视为单个值。例如,'%d %d' % [2, 3]TypeError,因为您尝试将列表传递给第一个 %d,而没有将任何值传递给第二个 %d。 (但是,也有反例,例如 max...)
这很有趣,我不知道在 python 标准库中有任何这样的例子。你说几个地方?
您将从这个答案中获得的价值在很大程度上取决于您执行的 Python 编程类型。如果您正在进行科学/统计编程,您可能会发现 numpy 示例非常突出。这也是一个常见的面试问题,所以 numpy 是一个非常有用的例子,可以放在你的口袋里。
T
Thiago Figueiro

这是 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 语法”区别是特定元组的元素是不可变的,而列表是可变的(...所以只有元组是可散列的,可以用作字典/散列键!)。这导致了它们如何使用或不能使用的差异(通过语法先验地强制执行)以及人们选择使用它们的方式的差异(被鼓励为“最佳实践”,后验,这就是聪明的程序员所做的)。区分何时使用元组与何时使用列表的主要区别在于人们赋予元素顺序的含义。

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

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

流行文化中的人和程序员不符合这些差异的例子不胜枚举,也有不计其数的人可能会在主菜中使用沙拉叉。归根结底,这很好,两者通常都能完成工作。

总结一些更精细的细节

相似之处:

重复 - 元组和列表都允许重复索引、选择和切片 - 元组和列表都使用括号内的整数值进行索引。因此,如果您想要给定列表或元组的前 3 个值,语法将是相同的:>>> my_list[0:3] [0,1,2] >>> my_tuple[0:3] [a ,b,c] 比较和排序 - 两个元组或两个列表都通过它们的第一个元素进行比较,如果存在平局,则通过第二个元素进行比较,依此类推。在前面的元素表现出差异之后,不再关注后面的元素。 >>> [0,2,0,0,0,0]>[0,0,0,0,0,500] 真 >>> (0,2,0,0,0,0)>(0,0 ,0,0,0,500) 真

差异: - 先验,根据定义

语法 - 列表使用 [],元组使用 () 可变性 - 给定列表中的元素是可变的,给定元组中的元素是不可变的。 # 列表是可变的: >>> 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'] # 元组是不可变的:>>> 名人元组 ('John', 'Wayne', 90210, ' Actor', 'Male', 'Dead') >>> lucky_tuple[5] 'Dead' >>> lucky_tuple[5]="Alive" Traceback(最近一次通话最后):文件“”,第 1 行,在 TypeError: 'tuple' object does not support item assignment Hashtables (Dictionaries) - 由于 hashtables (dictionaries) 要求其键是可散列的,因此是不可变的,因此只有元组可以充当字典键,而不是列表。 #Lists 不能充当哈希表(字典)的键 >>> my_dict = {[a,b,c]:"some value"} Traceback(最近一次调用最后):文件“”,第 1 行,在 TypeError: unhashable type: 'list' #Tuples CAN 作为 hashtables(dictionaries) 的键 >>> my_dict = {("John","Wayne"): 90210} >>> my_dict {('John' , '韦恩'): 90210}

差异 - 使用中的后验

Homo vs. Heterogeneity of Elements - 通常列表对象是同质的,而元组对象是异构的。也就是说,列表用于相同类型的对象/主题(如所有总统候选人,或所有歌曲,或所有跑步者),尽管它不是强制的),而元组更多用于异构对象。循环与结构 - 虽然两者都允许循环(对于 my_list 中的 x...),但对列表执行此操作才真正有意义。元组更适合结构化和呈现信息(位于 %s 中的 %s %s 是 %s,现在是 %s % ("John","Wayne",90210, "Actor","Dead"))


我喜欢 hashtable/hashable 示例来解释不变性的原因——你可以使用 tuple(record/struct/coordinate/vector/point) 作为 dict 的复杂键。
b
bluish

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

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

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


b
bluish

列表的值可以随时更改,但元组的值不能更改。

优点和缺点取决于用途。如果你有这样一个你不想改变的数据,那么你应该使用元组,否则列表是最好的选择。


M
M.Innat

列表和元组的区别

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

字面量语法 我们使用括号 () 来构造元组和方括号 [ ] 来获得一个新列表。此外,我们可以使用适当类型的调用来获取所需的结构——元组或列表。 someTuple = (4,6) someList = [2,6] 可变性 元组是不可变的,而列表是可变的。这一点是以下几点的基础。内存使用由于可变性,列表需要更多内存,元组需要更少内存。扩展 您可以向元组和列表添加新元素,唯一的区别是元组的 id 将被更改(即,我们将拥有一个新对象)。散列元组是可散列的,而列表则不是。这意味着您可以将元组用作字典中的键。列表不能用作字典中的键,而可以使用元组 tup = (1,2) list_ = [1,2] c = {tup : 1} # ok c = {list_ : 1} # error Semantics 这一点更多的是关于最佳实践。您应该将元组用作异构数据结构,而列表是同质序列。


p
pquers

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


在这一点上,这个答案并没有增加任何讨论,因为还有许多其他更好的答案。
D
Deepak Kr Gupta

正如人们已经在这里回答的那样,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 保持不变,没有任何例外


如果您解释说“即使元组本身是不可变的,这些也可以更改”,这篇文章将会得到改进。是因为这些对象保留了它们的身份(所以元组没有改变,因为它仍然包含相同的对象......)。
A
Antti Haapala -- Слава Україні

PEP 484 -- Type Hints 表示 tuple 的元素类型可以单独键入;这样你就可以说Tuple[str, int, float];但是一个 list,带有 List 类型的类只能接受一个类型参数:List[str],这暗示了 2 的区别实际上是前者是异构的,而后者本质上是同质的。

此外,标准库大多使用元组作为标准函数的返回值,其中 C 将返回 struct


P
Pygirl

正如人们已经提到的差异,我将写下为什么要使用元组。

为什么首选元组?

小元组的分配优化为了减少内存碎片并加快分配速度,Python 重用了旧的元组。如果一个元组不再需要并且少于 20 个项目而不是永久删除它,Python 会将其移动到空闲列表中。一个空闲列表分为 20 个组,每个组代表一个长度为 0 到 20 之间的元组列表。每个组最多可以存储 2000 个元组。第一个(零)组仅包含 1 个元素并表示一个空元组。

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


k
krunal kp

最重要的区别是时间!当您不想更改列表内的数据时,最好使用元组!这是为什么使用元组的示例!

import timeit
print(timeit.timeit(stmt='[1,2,3,4,5,6,7,8,9,10]', number=1000000)) #created list
print(timeit.timeit(stmt='(1,2,3,4,5,6,7,8,9,10)', number=1000000)) # created tuple 

在这个例子中,我们执行了这两个语句 100 万次

输出 :

0.136621
0.013722200000000018

任何人都可以清楚地注意到时差。


A
Albus Dumbledore

5.3. Tuples and Sequences 上文档的方向引用:

尽管元组可能看起来类似于列表,但它们通常用于不同的情况和不同的目的。元组是不可变的,并且通常包含通过解包(参见本节后面部分)或索引(甚至在命名元组的情况下通过属性)访问的异构元素序列。列表是可变的,它们的元素通常是同质的,可以通过遍历列表来访问。


A
Ayeni Lawrence

换句话说,TUPLES 用于存储组的内容/成员不会更改的元素组,而 LISTS 用于存储组成员可以更改的元素组。

例如,如果我想将网络的 IP 存储在变量中,最好使用元组,因为 IP 是固定的。像这个my_ip = ('192.168.0.15', 33, 60)。但是,如果我想存储我将在接下来的 6 个月内访问的地方的 IP 组,那么我应该使用 LIST,因为我会不断更新并向组中添加新 IP。像这样

places_to_visit = [
    ('192.168.0.15', 33, 60), 
    ('192.168.0.22', 34, 60), 
    ('192.168.0.1', 34, 60), 
    ('192.168.0.2', 34, 60), 
    ('192.168.0.8', 34, 60), 
    ('192.168.0.11', 34, 60)
] 

P
Peter Mortensen

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

元组,元素的有序序列(可以包含任何没有别名问题的对象)不可变(元组,int,float,str)使用+连接(当然将创建全新的元组)索引切片单例(3,)#-> (3) 而不是 (3) # -> 3

不可变(元组、int、float、str)

使用 + 连接(当然会创建全新的元组)

索引

切片

单例 (3,) # -> (3) 而不是 (3) # -> 3

列表(其他语言中的数组),有序值序列 可变单例 [3] 克隆 new_array = origin_array[:] 列表理解 [x**2 for x in range(1,7)] 为您提供 [1,4,9, 16,25,36](不可读)

可变的

单身人士 [3]

克隆 new_array = origin_array[:]

列表理解 [x**2 for x in range(1,7)] 为您提供 [1,4,9,16,25,36](不可读)

使用 list 还可能导致别名错误(指向同一对象的两个不同路径)。


S
San Askaruly

只是对list vs tuple 响应的快速扩展:

由于动态特性,列表分配的位桶比实际所需的内存多。这样做是为了防止在将来附加额外项目时进行昂贵的重新分配操作。

另一方面,作为静态的轻量级元组对象,不会保留存储它们所需的额外内存。


这些比特桶只是未来项目的额外“空间”吗?它是如何确定桶的大小和数量的?
J
Jonathan Leffler

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

a = ["1", "2", "ra", "sa"]    #list
b = ("1", "2", "ra", "sa")    #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.

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


s
sss_coder

列表是可变的。而元组是不可变的。在元组中访问具有索引的偏移元素比列表更有意义,因为元素及其索引不能更改。


T
Tony

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

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

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


虽然其中一些在技术上是正确的,但这并不是可变类型和不可变类型之间的关键区别。更大的区别是可变类型可以在构造后更改,而不可变类型不能。
这也不是原因。内存和可变性彼此无关。这只是特定于列表的实现细节。内存也没有分配给变量,而是分配给对象。然后变量只是对这些对象的引用。
A
Andrew Ramshaw

除了这里提出的许多其他评论外,我看到使用元组的好处是它们能够具有不同类型的值而不像列表的灵活性。

以一个数据库表为例,它为每一列指定了不同的值和类型。列表根本无法复制这一点(因为它限制为它可以包含的单一类型的值),而元组可以有多种不同的类型和值,并且它们的位置在每列中都得到尊重(甚至可以放在列表中创建自己的数据库虚拟表示)。

这种灵活性和限制(因为不能更改值)也有它的好处,比如传输事务数据(或者说类似于表格的格式)。您“密封”元组中的数据,防止它在发送保护它之前被修改,因为它的设计目的是:提供不变性。与只读集合相比,这有什么区别?您可以有不同的值类型的事实。

它的应用(因为列表、对象和字典的大量使用)受到限制,人们通常认为对象模型可以作为更好的选择(在某些情况下确实如此),但是说你不'不需要对象模型,因为您更愿意将其与您定义为业务实体的内容分开。然后,一个元组可能会很好地为您提供您想要实现的目标。