Lists 和 Tuples 大对决

发布于 2025-01-06 13:57:34 字数 3747 浏览 8 评论 0

常见的 Python 初学者问题:列表和元组之间有何区别?答案是,有两个不同的差异,以及两者之复杂的相互作用。这就是技术差异和文化差异。

首先:它们有相同之处:列表和元组都是容器,即对象序列:

>>> my_list = [1, 2, 3]  
>>> type(my_list)  
<class 'list'>  
>>> my_tuple = (1, 2, 3)  
>>> type(my_tuple)  
<class 'tuple'>

它们任意一个的元素可以是任意类型,甚至在一个单一序列中。它们都维护元素的顺序(不像集合和字典那样)。现在是不同之处。列表和元组之间的技术差异是,列表示可变的(可以被改变),而元组是不可变的(不可以被改变)。这是 Python 语言对它们的唯一区分:

>>> my_list[1] = "two"  
>>> my_list  
[1, 'two', 3]  
>>> my_tuple[1] = "two"  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
TypeError: 'tuple' object does not support item assignment

这就是列表和元组之间的唯一技术差异,虽然它体现在几个方面。例如,列表有一个.append() 方法,用以添加更多元素到列表中,而元组并没有:

>>> my_list.append("four")  
>>> my_list  
[1, 'two', 3, 'four']  
>>> my_tuple.append("four")  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
AttributeError: 'tuple' object has no attribute 'append'

元组并不需要.append() 方法,因为你不可以修改元组。文化差异是关于列表和元组的实际使用的:当你有一个未知长度的同质序列时使用列表;当你预先知道元素个数的时候使用元组,因为元素的位置语义上是显著的。

例如,假设你有一个函数,它查找目录下以*.py 结尾的文件。它应该返回一个列表,因为你并不知道会找到多少个文件,而它们都具有相同的语义:只是你找到的另一个文件。

>>> find_files("*.py")  
["control.py", "config.py", "cmdline.py", "backward.py"]

另外,假设你需要存储五个值来表示气象观测站的位置:id, city, state, latitude 和 longitude。那么较之列表,元组更适合:

>>> denver = (44, "Denver", "CO", 40, 105)  
>>> denver[1]  
'Denver'

目前,不要讨论使用类来替代,这里,第一个元素是 id,第二个元素是 city,以此类推。位置决定了意思。将文化差异加之于 C 语言上,列表像数组,元组像结构。

Python 有一个 namedtuple 工具,它可以让意思更加明确:

>>> from collections import namedtuple  
>>> Station = namedtuple("Station", "id, city, state, lat, long")  
>>> denver = Station(44, "Denver", "CO", 40, 105)  
>>> denver  
Station(id=44, city='Denver', state='CO', lat=40, long=105)  
>>> denver.city  
'Denver'  
>>> denver[1]  
'Denver'

元组和列表之间的文化差异一个聪明的总结是:元组是没有名字的 namedtuple。

技术差异和文化差异是一个不稳定的联盟,因为有时它们相左。为什么同源序列应该可变,而异源序列不是?例如,因为 namedtuple 是一个元组,它是不可变的,所以我不可以修改我的气象站:

 denver.lat = 39.7392  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
AttributeError: can't set attribute

有时,技术方面的考虑覆盖了文化因素。你不能把一个列表当做一个字典键,因为只有不可变值才能够被哈希,所以只有不可变值才能作为键。要把一个列表当成键,你可以将其转换成元组:

 d = {}  
>>> nums = [1, 2, 3]  
>>> d[nums] = "hello"  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
TypeError: unhashable type: 'list'  
>>> d[tuple(nums)] = "hello"  
>>> d  
{(1, 2, 3): 'hello'}

另一个技术和文化的冲突是:Python 自身在使用列表更有意义的情况下使用了元组。当你使用*args 定义一个函数时,args 作为元组传递,即使据 Python 所知,值的位置并不重要。你可能会说,它是元组,因为你不可以改变你所传递的值,但这只是较之文化,更重视了技术差异。

我知道,我知道,在 args 中,位置可能是重要的,因为它们是位置参数。但在一个接受 args,然后将其传递给另一个函数的函数中,它只是一个参数序列,和另一个没什么不同,而它们的数量在调用之间可以不同。

这里,Python 使用元组,是因为较之列表,它们的空间效率会多一点。列表是过度分配的,以便让附加更快些。这说明 Python 务实的一面:因地制宜使用数据结构,而不是纠结于*args 的列表/元组语义。

在大多数情况下,你应该基于文化差异选择是使用列表还是元组。想想你的数据的含义。如果基于你的程序在现实世界中遇到的,它会有不同的长度,那么可能要使用列表。如果你知道在你写代码的时候,第三个元素意味着什么,那么可能要使用元组。

另一方面,函数式编程强调不可变数据结构,作为一种避免难以推理代码这一副作用的方式。如果你是一个函数式编程粉,那么你可能会因为不可变性喜欢元组。

所以:你应该使用元组还是列表呢?答案是:它并不总是一个简单的答案。

原文: Lists vs. Tuples

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
26 人气
更多

推荐作者

李珊平

文章 0 评论 0

Quxin

文章 0 评论 0

范无咎

文章 0 评论 0

github_ZOJ2N8YxBm

文章 0 评论 0

若言

文章 0 评论 0

南…巷孤猫

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文