有什么不同?
元组/列表的优点/缺点是什么?
除了元组是不可变的之外,还有一个语义区别应该指导它们的使用。元组是异构数据结构(即它们的条目具有不同的含义),而列表是同构序列。元组有结构,列表有顺序。
使用这种区别使代码更加明确和易于理解。
一个例子是成对的页码和行号来引用书中的位置,例如:
my_location = (42, 11) # page number, line number
然后,您可以将其用作字典中的键来存储有关位置的注释。另一方面,列表可用于存储多个位置。自然地,人们可能想要在列表中添加或删除位置,因此列表是可变的是有道理的。另一方面,从现有位置添加或删除项目没有意义 - 因此元组是不可变的。
在某些情况下,您可能想要更改现有位置元组中的项目,例如在遍历页面行时。但是元组不变性迫使您为每个新值创建一个新的位置元组。从表面上看,这似乎很不方便,但使用像这样的不可变数据是值类型和函数式编程技术的基石,它可以具有很大的优势。
关于这个问题有一些有趣的文章,例如“Python 元组不仅仅是常量列表”或“理解 Python 中的元组与列表”。Python 官方文档也提到了这一点
“元组是不可变的,通常包含异构序列......”。
在像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 # 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
用法
由于列表是可变的,它不能用作字典中的键,而可以使用元组。
a = (1,2)
b = [1,2]
c = {a: 1} # OK
c = {b: 1} # Error
如果你去散步,你可以随时在一个(x,y)
元组中记录你的坐标。
如果您想记录您的旅程,您可以每隔几秒钟将您的位置附加到一个列表中。
但是你不能反过来做。
关键区别在于元组是不可变的。这意味着一旦创建元组,就不能更改元组中的值。
因此,如果您需要更改值,请使用列表。
元组的好处:
列表是可变的;元组不是。
来自docs.python.org/2/tutorial/datastructures.html
元组是不可变的,并且通常包含通过解包(参见本节后面部分)或索引(甚至在命名元组的情况下通过属性)访问的异构元素序列。列表是可变的,它们的元素通常是同质的,可以通过遍历列表来访问。
有人提到,区别主要是语义上的:人们期望一个元组和一个列表来表示不同的信息。但这不仅仅是指导方针;一些库实际上根据它们传递的内容而表现不同。以 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 中,列表和元组是完全不同的东西。
这是 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]
True
>>> (0,2,0,0,0,0)>(0,0,0,0,0,500)
True
差异: - 先验,根据定义
语法- 列表使用 [],元组使用 ()
可变性- 给定列表中的元素是可变的,给定元组中的元素是不可变的。
# 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
Hashtables (Dictionaries) - 由于 hashtables (dictionaries) 要求其键是可散列的,因此是不可变的,因此只有元组可以充当字典键,而不是列表。
#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}
差异 - 使用中的后验
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
语义
这一点更多的是关于最佳实践。您应该将元组用作异构数据结构,而列表是同质序列。
列表旨在成为同质序列,而元组是异构数据结构。
正如人们已经在这里回答的那样tuples
,不可变而lists
可变,但是我们必须记住使用元组的一个重要方面
如果其中tuple
包含 alist
或 a 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说 a 的元素类型可以tuple
单独输入;这样你就可以说Tuple[str, int, float]
;但是 a list
, with List
typing class 只能接受一个类型参数:List[str]
,这暗示了 2 的区别实际上是前者是异构的,而后者本质上是同质的。
此外,标准库主要使用元组作为 C 将返回 a 的标准函数的返回值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
任何人都可以清楚地注意到时差。
尽管元组可能看起来类似于列表,但它们通常用于不同的情况和不同的目的。元组是不可变的,通常包含一个异构的元素序列,这些元素通过解包(见本节后面)或索引(或者在命名元组的情况下甚至通过属性)访问。列表是可变的,它们的元素通常是同质的,可以通过遍历列表来访问。
首先,它们都是 Python 中的非标量对象(也称为复合对象)。
+
(当然会创建全新的元组)(3,) # -> (3)
而不是(3) # -> 3
[3]
new_array = origin_array[:]
[x**2 for x in range(1,7)]
给你
[1,4,9,16,25,36]
(不可读)使用 list 还可能导致别名错误(指向同一对象的两个不同路径)。
list
只是对vs tuple
响应的快速扩展:
由于动态特性,list
分配比实际所需内存更多的位桶。这样做是为了防止在将来附加额外项目时进行昂贵的重新分配操作。
另一方面,作为静态的轻量级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 个字节)。
但是,如果您知道自己不经常添加新元素,那么您应该使用元组。元组精确分配所需内存的大小,从而节省内存,尤其是在您使用大块内存时。