元组/列表之间有什么区别,它们的优点/缺点是什么?
list
。 ;D
除了元组是不可变的之外,还有一个语义区别应该指导它们的使用。元组是异构数据结构(即它们的条目具有不同的含义),而列表是同构序列。元组有结构,列表有顺序。
使用这种区别使代码更加明确和易于理解。
一个例子是成对的页码和行号来引用书中的位置,例如:
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,这是有道理的,因为元组已经应该具有结构。这强调了元组是类和实例的轻量级替代方案。
列表和元组的区别
字面量 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} # 错误
3. Permitted operation
下的第一个框首先显示了元组的情况。我知道显示成功然后显示错误是很常见的,但这让我的头脑混乱了片刻。
one_item_list = [a]
,但one_tuple = (a,)
是对应的元组。注意变量名后面的逗号。但还要注意 two_tuple = (a, b)
。这不止一次让我失望(在 Python 3 中仍然存在)。
tuple(sorted(the_unsorted_tuple))
如果您去散步,您可以随时在 (x,y)
元组中记录您的坐标。
如果您想记录您的旅程,您可以每隔几秒钟将您的位置附加到一个列表中。
但是你不能反过来做。
关键区别在于元组是不可变的。这意味着一旦创建元组,就不能更改元组中的值。
因此,如果您需要更改值,请使用列表。
元组的好处:
性能略有提升。由于元组是不可变的,它可以用作字典中的键。如果你不能改变它,其他人也不能,也就是说你不需要担心任何 API 函数等。在不被询问的情况下改变你的元组。
frozenset
或各种第三方冻结的 dict/tree/etc。类型,但这些都不允许您添加可变元素。 (当然,一个元组只有在它的所有元素都是可散列的,它以通常的 EAFP 方式处理,所以 d[1, [2]]
将引发 TypeError: unhashable type: 'list'
。)
列表是可变的;元组不是。
来自docs.python.org/2/tutorial/datastructures.html
元组是不可变的,并且通常包含通过解包(参见本节后面部分)或索引(甚至在命名元组的情况下通过属性)访问的异构元素序列。列表是可变的,它们的元素通常是同质的,可以通过遍历列表来访问。
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)
的库代码分支都会表现不同
'%d %d' % [2, 3]
是 TypeError
,因为您尝试将列表传递给第一个 %d
,而没有将任何值传递给第二个 %d
。 (但是,也有反例,例如 max
...)
这是 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(最近一次通话最后):文件“
差异 - 使用中的后验
Homo vs. Heterogeneity of Elements - 通常列表对象是同质的,而元组对象是异构的。也就是说,列表用于相同类型的对象/主题(如所有总统候选人,或所有歌曲,或所有跑步者),尽管它不是强制的),而元组更多用于异构对象。循环与结构 - 虽然两者都允许循环(对于 my_list 中的 x...),但对列表执行此操作才真正有意义。元组更适合结构化和呈现信息(位于 %s 中的 %s %s 是 %s,现在是 %s % ("John","Wayne",90210, "Actor","Dead"))
列表用于循环,元组用于结构,即"%s %s" %tuple
。
列表通常是同质的,元组通常是异构的。
列表用于可变长度,元组用于固定长度。
列表的值可以随时更改,但元组的值不能更改。
优点和缺点取决于用途。如果你有这样一个你不想改变的数据,那么你应该使用元组,否则列表是最好的选择。
列表和元组的区别
元组和列表都是 Python 中看似相似的序列类型。
字面量语法 我们使用括号 () 来构造元组和方括号 [ ] 来获得一个新列表。此外,我们可以使用适当类型的调用来获取所需的结构——元组或列表。 someTuple = (4,6) someList = [2,6] 可变性 元组是不可变的,而列表是可变的。这一点是以下几点的基础。内存使用由于可变性,列表需要更多内存,元组需要更少内存。扩展 您可以向元组和列表添加新元素,唯一的区别是元组的 id 将被更改(即,我们将拥有一个新对象)。散列元组是可散列的,而列表则不是。这意味着您可以将元组用作字典中的键。列表不能用作字典中的键,而可以使用元组 tup = (1,2) list_ = [1,2] c = {tup : 1} # ok c = {list_ : 1} # error Semantics 这一点更多的是关于最佳实践。您应该将元组用作异构数据结构,而列表是同质序列。
列表旨在成为同质序列,而元组是异构数据结构。
正如人们已经在这里回答的那样,tuples
是不可变的,而 lists
是可变的,但是我们必须记住使用元组的一个重要方面
如果 tuple
中包含 list
或 dictionary
,即使 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})
发生这种情况是因为 list
和 dictionary
是对象,这些对象并没有改变,而是它指向的内容。
所以 tuple
保持不变,没有任何例外
PEP 484 -- Type Hints 表示 tuple
的元素类型可以单独键入;这样你就可以说Tuple[str, int, float]
;但是一个 list
,带有 List
类型的类只能接受一个类型参数:List[str]
,这暗示了 2 的区别实际上是前者是异构的,而后者本质上是同质的。
此外,标准库大多使用元组作为标准函数的返回值,其中 C 将返回 struct
。
正如人们已经提到的差异,我将写下为什么要使用元组。
为什么首选元组?
小元组的分配优化为了减少内存碎片并加快分配速度,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
最重要的区别是时间!当您不想更改列表内的数据时,最好使用元组!这是为什么使用元组的示例!
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
任何人都可以清楚地注意到时差。
5.3. Tuples and Sequences 上文档的方向引用:
尽管元组可能看起来类似于列表,但它们通常用于不同的情况和不同的目的。元组是不可变的,并且通常包含通过解包(参见本节后面部分)或索引(甚至在命名元组的情况下通过属性)访问的异构元素序列。列表是可变的,它们的元素通常是同质的,可以通过遍历列表来访问。
换句话说,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)
]
首先,它们都是 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 还可能导致别名错误(指向同一对象的两个不同路径)。
只是对list
vs tuple
响应的快速扩展:
由于动态特性,列表分配的位桶比实际所需的内存多。这样做是为了防止在将来附加额外项目时进行昂贵的重新分配操作。
另一方面,作为静态的轻量级元组对象,不会保留存储它们所需的额外内存。
列表是可变的,元组是不可变的。只要考虑这个例子。
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.
因此证明以下代码对元组无效,因为我们试图更新一个元组,这是不允许的。
列表是可变的。而元组是不可变的。在元组中访问具有索引的偏移元素比列表更有意义,因为元素及其索引不能更改。
列表是可变的,元组是不可变的。可变和不可变之间的主要区别在于尝试追加项目时的内存使用情况。
创建变量时,会为变量分配一些固定内存。如果是列表,则分配的内存比实际使用的多。例如,如果当前内存分配是 100 字节,当您想要附加第 101 个字节时,可能会分配另外 100 个字节(在这种情况下总共 200 个字节)。
但是,如果您知道自己不经常添加新元素,那么您应该使用元组。元组精确分配所需内存的大小,从而节省内存,尤其是在您使用大块内存时。
除了这里提出的许多其他评论外,我看到使用元组的好处是它们能够具有不同类型的值而不像列表的灵活性。
以一个数据库表为例,它为每一列指定了不同的值和类型。列表根本无法复制这一点(因为它限制为它可以包含的单一类型的值),而元组可以有多种不同的类型和值,并且它们的位置在每列中都得到尊重(甚至可以放在列表中创建自己的数据库虚拟表示)。
这种灵活性和限制(因为不能更改值)也有它的好处,比如传输事务数据(或者说类似于表格的格式)。您“密封”元组中的数据,防止它在发送保护它之前被修改,因为它的设计目的是:提供不变性。与只读集合相比,这有什么区别?您可以有不同的值类型的事实。
它的应用(因为列表、对象和字典的大量使用)受到限制,人们通常认为对象模型可以作为更好的选择(在某些情况下确实如此),但是说你不'不需要对象模型,因为您更愿意将其与您定义为业务实体的内容分开。然后,一个元组可能会很好地为您提供您想要实现的目标。
collections.namedtuple
称为collections.record
会更好。例如,交换客户记录中的姓名和地址是没有意义的;事实上,这样做通常会是一个错误,元组的不变性会阻止您提交。What would you do with such a list?
,当人们使用缺乏幻想作为论据时,我总是发抖。使用混合类型列表非常有效,例如对于某些分层数据结构,其中每个列表都由子列表和值元素组成。