Python 元组与列表:异同,解释

深入探究:Python元组与列表的对比分析

本指南将带您深入了解Python中元组和列表的相似之处与差异。此外,您将了解在何种情境下应优先考虑使用元组。

列表和元组是Python中两种基本的数据结构,它们都可以用来存储一系列元素。

尽管元组和列表在支持索引、切片以及容纳多种数据类型等方面具有相似的功能,理解它们之间的差异对于选择合适的数据结构至关重要。

让我们开始探索吧。

👩🏽‍💻 您可以启动Python交互式解释器(REPL)并跟随本教程进行操作。或者,您也可以使用在线Python编辑器进行编码。

Python 元组与列表:共性解析

首先,让我们研究列表和元组之间的相似之处,并通过实例来加深理解。

#1. Python 中的可迭代对象

在Python中,列表用方括号[]括起来,而元组则用圆括号()括起来。您也可以直接使用逗号分隔的值来创建元组,而无需括号。

两者都是可迭代的,这意味着您可以使用for循环来遍历它们。

以下代码展示了如何遍历一个列表:

nums = [2,6,7,10]
print(f"nums 的类型是 {type(nums)}")
for num in nums:
  print(num)

# 输出
nums 的类型是 <class 'list'>
2
6
7
10

同样,您可以使用循环来遍历元组:

nums = (2,6,7,10)

# 注意:nums = 2,6,7,10 也是一个合法的元组。 如果需要,请快速验证!

print(f"nums 的类型是 {type(nums)}")
for num in nums:
  print(num)

# 输出
nums 的类型是 <class 'tuple'>
2
6
7
10

#2. 从其他序列创建

列表和元组的另一个共同点是它们都可以从现有序列(如字符串)创建。

sample_str = "Coding!"

下面的代码演示了如何使用 list(string) 从字符串创建列表:

list_from_str = list(sample_str)
print(list_from_str)

# 输出
['C', 'o', 'd', 'i', 'n', 'g', '!']

类似地,可以使用 tuple(sequence) 从字符串或其他序列创建元组。如下所示:

tuple_from_str = tuple(sample_str)
print(tuple_from_str)

# 输出
('C', 'o', 'd', 'i', 'n', 'g', '!')

#3. 支持索引和切片

Python支持零索引,这意味着第一个元素的索引是0,第二个是1,以此类推。此外,Python还支持负索引,其中最后一个元素的索引是-1,倒数第二个元素的索引是-2,以此类推。

list_from_str = ['C', 'o', 'd', 'i', 'n', 'g', '!']
print(list_from_str[1])
# o

索引为 -2 的元素是倒数第二个元素 “g”。

tuple_from_str = ('C', 'o', 'd', 'i', 'n', 'g', '!')
print(tuple_from_str[-2])
# g

当您需要处理列表或元组的一部分时,可以使用切片。 list[start:end] 返回从索引 start 开始,到索引 end - 1 结束的列表切片。start 的默认值为 0,end 默认是可迭代对象的最后一个元素。

您可以使用相同的语法对元组进行切片。下面是如何对之前创建的列表和元组进行切片的示例。

list_from_str = ['C', 'o', 'd', 'i', 'n', 'g', '!']
print(list_from_str[0:5])

# 输出
['C', 'o', 'd', 'i', 'n']

除了起始和结束索引外,还可以指定步长值。 tuple[start:end:step] 返回从 startend-1 的元组切片,步长为 step

tuple_from_str = ('C', 'o', 'd', 'i', 'n', 'g', '!')
print(tuple_from_str[::2])

# 输出
('C', 'd', 'n', '!')

这里,我们将步长值设置为 2,因此切片包含每隔一个的元素。

#4. 多种数据类型的集合

在前面的例子中,列表和元组中的所有元素都具有相同的数据类型。

然而,您可以在单个列表或元组中存储不同数据类型的值。

在下面的代码中,student_list 包含了字符串类型的学生姓名、整数类型的年龄和浮点类型的分数。

student_list = ["John",22,96.5]
for item in student_list:
  print(f"{item} 的类型是 {type(item)}")

# 输出
John 的类型是 <class 'str'>
22 的类型是 <class 'int'>
96.5 的类型是 <class 'float'>

我们也可以使用类似的例子来演示元组:

student_tuple = ("Jane",23,99.5)
for item in student_tuple:
  print(f"{item} 的类型是 {type(item)}")

# 输出
Jane 的类型是 <class 'str'>
23 的类型是 <class 'int'>
99.5 的类型是 <class 'float'>

#5. 支持成员测试

列表和元组都允许您执行成员测试,以检查是否存在特定项目。您可以使用 in 运算符来检查列表或元组中是否存在特定项目。

如果 iterable 包含 item,则表达式 item in iterable 的计算结果为 True; 否则,为 False

"Alex" in student_list
# False

"Jane" in student_tuple
# True

到目前为止,您已经了解了Python中列表和元组之间的相似之处。接下来,让我们来看看这两种数据结构之间的主要区别。

Python 元组与列表:差异解析

#1. 列表的可变性与元组的不可变性

列表和元组之间最重要的区别在于元组是不可变的。这意味着您不能在原地修改元组。

▶️ 这是一个例子。

tuple1 = ("Java","Python","C++")
tuple1[0] = "Rust"

# 输出
----> 2 tuple1[0] = "Rust"

TypeError: 'tuple' 对象不支持项赋值

列表是一种可变的数据结构,因此我们可以通过更改特定索引处的项目来修改列表,如下面的代码所示。

list1 = ["Java","Python","C++"]
list1[0] = "Rust"
print(list1)

# 输出
['Rust', 'Python', 'C++']

#2. 可变长度的列表与固定长度的元组

Python列表是一种可变长度的数据结构。

您可以执行以下操作:

  • 向列表末尾添加项目
  • 将另一个列表中的项目添加到当前列表的末尾
  • 从列表中删除特定索引处的项目
list1 = [2,3,4,5]

# 添加一个项目到末尾
list1.append(9)
print(list1)

# 将 list2 中的项目添加到 list1 的末尾
list2 = [0,7]
list1.extend(list2)
print(list1)

# 从 list1 中删除一个项目
list1.pop(0)
print(list1)

▶️ 上述代码片段的输出。

# 输出
[2, 3, 4, 5, 9]
[2, 3, 4, 5, 9, 0, 7]
[3, 4, 5, 9, 0, 7]

元组是固定长度的数据结构。因此,您不能在现有元组中添加或删除元素。但是,您可以重新定义元组以包含不同的元素。

tuple1 = (2,4,6,8)
tuple1 = (1,8,9)
print(tuple1)

# 输出
(1, 8, 9)

#3. 内存占用

列表是一种可变长度的数据结构。最初定义列表时,会在内存中为其分配特定的大小。当您使用 append()extend() 方法修改列表时,需要分配额外的内存来存储添加的元素。这种分配几乎总是比您添加的元素数量多。

因此,需要跟踪列表中项目的数量和分配的空间。此外,由于列表的长度是可变的,因此有一个指针指向列表项的地址。因此,长度为 k 的列表比具有相同 k 个元素的元组占用更多的内存。

这是一个简单的图示。

您可以使用内置的 sys 模块中的 getsizeof() 方法获取Python对象在内存中的大小。

import sys

list1 = [4,5,9,14]
list_size = sys.getsizeof(list1)
print(f"列表大小:{list_size}")

tuple1 = (4,5,9,14)
tuple_size = sys.getsizeof(tuple1)
print(f"元组大小:{tuple_size}")

对于相同数量和值的元素,列表比元组占用更多内存,如下面的输出所示。

# 输出
列表大小:104
元组大小:88

何时应使用Python元组?

从Python列表和元组的比较中可以看出,如果您需要一个可变的集合,则应使用列表。

那么何时应该使用元组呢?

我们将在本节中讨论。

#1. 只读集合

每当您需要一个不可变的集合时,都应该将其定义为元组。例如, color = (243, 55, 103) 是一个元组,其中包含对应于颜色阴影的RGB值。将颜色定义为元组可以确保其不可修改。

本质上,当您需要一个集合是只读的,即在程序运行时不应该修改其值时,您应该考虑使用元组。这将防止对值的意外修改。

#2. 字典的键

假设您使用列表项 key_list 作为键创建字典。您可以使用 dict.fromkeys() 方法从列表创建字典。

key_list = list("ABCD")
dict.fromkeys(key_list)

# 输出
{'A': None, 'B': None, 'C': None, 'D': None}

假设您在创建字典之前修改了列表,使”D”成为第一个元素(索引0)。

现在,字典键 “A” 会发生什么?

如果您尝试从 key_list 创建字典并访问与键 “A” 对应的值,则会遇到 KeyError

key_list[0] = 'D'

dict.fromkeys(key_list)['A']

# 输出
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-31-c90392acc2cf> in <module>()
----> 1 dict.fromkeys(key_list)['A']

KeyError: 'A'

字典的键应该是唯一的。因此,您不能有第二个 ‘D’ 作为键。

dict.fromkeys(key_list)
# 输出
{'B': None, 'C': None, 'D': None} # A 不再是一个键。

如果您改为使用元组,则不可能进行此类修改,并且您不太可能遇到错误。因此,您应该更喜欢使用元组的项目作为键来创建字典。

key_tuple = tuple("ABCD")
dict.fromkeys(key_tuple)
# 输出
{'A': None, 'B': None, 'C': None, 'D': None}

key_tuple[0] = 'D'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-12-2cecbefa7db2> in <module>()
----> 1 key_tuple[0] = 'D'

TypeError: 'tuple' 对象不支持项赋值

#3. 函数参数

元组的不可变性也使得它们适合作为函数参数传入。

考虑以下函数 find_volume(),它返回给定尺寸的长方体体积:长度、宽度和高度。

def find_volume(dimensions):
  l,b,h = dimensions
  return l*b*h

假设这些维度在一个名为 dimensions 的列表中可用。以维度作为参数调用 find_volume() 将返回体积。

dimensions = [2,8,5]
find_volume(dimensions)
# 输出
80

您始终可以更改列表中存储的维度。

dimensions = [20,8,5]
find_volume(dimensions)
# 输出
800

但是,有时您需要这些值保持不变并且不能修改。这时,您应该考虑将参数存储为元组并在函数调用中使用它们。

#4. 函数的返回值

在Python中,您会在函数的返回值中遇到元组。当您从函数返回多个值时,Python会隐式地将它们作为元组返回。

考虑以下函数 return_even():

def return_even(num):
  even = [i for i in range(num) if (i%2==0)]
  return even,len(even)
  • 它需要一个数字 num 作为参数。
  • 它返回区间 [0,num) 中的偶数列表以及该列表的长度。

让我们将 num 的值设置为20并调用该函数。

num = 20

调用 return_even() 会以元组的形式返回两个值。您可以使用类型函数来验证返回值类型。

type(return_even(num)) # <class 'tuple'>

您可以打印返回值,以验证它是一个元组,其中第一个元素是偶数列表,第二个元素是该列表的长度。

print(return_even(num))
# 输出
([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], 10)

由于元组中有两个元素,因此您可以将它们解包为两个变量,如下所示。

even_nums, count = return_even(num)

print(even_nums)
print(count)

# 输出
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
10

结论

我希望本教程能够为您提供Python元组与列表的全面比较。

让我们通过一个快速总结来结束本教程:

  • 列表和元组是Python中的内置数据结构。
  • 相似之处:可迭代,支持索引,切片,不同的数据类型以及成员测试的运算符。
  • 关键区别:列表是可变的,而元组是不可变的。
  • 其他区别:元组的长度是固定的,而列表的长度是可变的;元组占用较少的内存。
  • 何时应该使用元组? 用于不可变的集合、字典的键和函数参数。

接下来,您可以尝试一些Python项目来练习和学习。或者学习从Python列表中删除重复项的方法。祝您学习愉快!编程快乐!👩🏽‍💻