列表与元组

ZaynPei Lv6

列表 (List)

列表是一个有序的可变的集合,可以包含任意类型的对象,例如数字、字符串、甚至其他列表。 列表使用方括号 [] 来定义,元素之间用逗号分隔。

  • 有序性 (Ordered):列表中的元素按照它们被添加的顺序进行存储。每个元素都有一个唯一的索引(位置编号),从 0 开始。
  • 可变性 (Mutable):你可以在列表创建后,随时添加删除修改其中的元素。
  • 异构性 (Heterogeneous):列表中可以包含不同数据类型的元素,比如整数、字符串和另一个列表同时存在。
  • 动态性 (Dynamic):列表的长度是动态变化的,可以根据需要增长或缩减。

创建列表

直接使用方括号 []:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建一个空列表
empty_list = []

# 创建一个包含整数的列表
numbers = [1, 2, 3, 4, 5]

# 创建一个包含字符串的列表
fruits = ["apple", "banana", "cherry"]

# 创建一个混合类型的列表
mixed_list = [1, "hello", 3.14, True, ["a", "b"]]

print(numbers) # 输出: [1, 2, 3, 4, 5]
print(mixed_list) # 输出: [1, 'hello', 3.14, True, ['a', 'b']]
也可以使用 list() 函数从其他可迭代对象(如字符串、元组或范围)创建列表:
1
2
3
4
5
6
7
8
# 从字符串创建列表
char_list = list("Python")
print(char_list) # 输出: ['P', 'y', 't', 'h', 'o', 'n']

# 从元组创建列表
tuple_example = (10, 20, 30)
tuple_to_list = list(tuple_example)
print(tuple_to_list) # 输出: [10, 20, 30]

访问列表元素(索引)

可以通过索引来访问列表中的单个元素, 正向索引从 0 开始, 反向索引从 -1 开始。

1
2
3
4
5
6
7
8
9
10
11
fruits = ["apple", "banana", "cherry", "date"]

# 正向索引 (从 0 开始)
print(fruits[0]) # 输出: 'apple'
print(fruits[2]) # 输出: 'cherry'
print(fruits[4]) # 报错: IndexError: list index out of range (索引超出范围)

# 反向索引 (从 -1 开始)
print(fruits[-1]) # 输出: 'date' (最后一个元素)
print(fruits[-2]) # 输出: 'cherry' (倒数第二个元素)
print(fruits[-5]) # 报错: IndexError: list index out of range (索引超出范围)

列表切片 (Slicing)

切片允许你提取列表的一个子集,通过指定起始结束索引来实现。切片的语法是 list[start:end:step]左闭右开, 其中: - start:切片的起始索引(包含该索引对应的元素), 如果省略,默认为 0。 - end:切片的结束索引(不包含该索引对应的元素), 如果省略,默认为列表末尾, 包含末尾元素。 - step:步长,表示每隔多少个元素取一个,默认为 1; 如果是负数, 则表示逆序取元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 获取索引 2 到 4 的元素 (索引 5 不包含)
print(numbers[2:5]) # 输出: [2, 3, 4]

# 获取从开头到索引 3 的元素
print(numbers[:4]) # 输出: [0, 1, 2, 3]

# 获取从索引 5 到末尾的元素
print(numbers[5:]) # 输出: [5, 6, 7, 8, 9]

# 获取整个列表的副本
print(numbers[:]) # 输出: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 每隔一个元素取一个
print(numbers[::2]) # 输出: [0, 2, 4, 6, 8]

# 倒着取元素
print(numbers[-2:-1:]) # 输出: [8] # 注意: -1 是结束索引, 不包含
print(numbers[-1:-2:]) # 输出: [] # 步长为正,起始索引在结束索引之后,结果为空列表
print(numbers[-1:-2:-1]) # 输出: [9] # 步长为负,起始索引在结束索引之后,可以取到元素

# 逆序列表
print(numbers[::-1]) # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

修改、添加和删除元素

由于列表是可变的,我们可以很方便地操作其内容。

修改元素: 直接通过索引赋值即可。

1
2
3
colors = ["red", "green", "blue"]
colors[1] = "yellow"
print(colors) # 输出: ['red', 'yellow', 'blue']

添加元素: - append():在列表末尾添加一个元素, 函数原型为 list.append(element)。 - insert():在指定索引位置插入一个元素, 函数原型为 list.insert(index, element)。 - extend():用另一个可迭代对象(如列表、元组、字符串等)扩展当前列表,将其中的所有元素添加到末尾。函数原型为 list.extend(iterable),这里参数不是专门限定为列表,而是任何可迭代对象,因此更灵活。

1
2
3
4
5
6
7
8
9
10
11
colors.append("purple")
print(colors) # 输出: ['red', 'yellow', 'blue', 'purple']

colors.insert(1, "orange") # 在索引 1 处插入 'orange'
print(colors) # 输出: ['red', 'orange', 'yellow', 'blue', 'purple']

more_colors = ["cyan", "magenta"]
colors.extend(more_colors)
print(colors) # 输出: ['red', 'orange', 'yellow', 'blue', 'purple', 'cyan', 'magenta']
colors.extend("pink") # 也可以传入字符串, 会把每个字符作为单独元素添加
colors.extend((1, 2, 3)) # 也可以传入元组

删除元素: - del 语句:根据索引删除元素, 语法为 del list[index], 注意 del 不是列表的方法, 而是 Python 的一个关键字。 - remove() 方法:根据删除第一个匹配的元素, 语法为 list.remove(value)。 - pop() 方法:删除并返回指定索引的元素, 可以用一个变量接受返回值. 如果不指定索引, 默认删除并返回最后一个元素, 语法为 list.pop([index])

1
2
3
4
5
6
7
8
9
del colors[1] # 删除索引为 1 的 'orange'
print(colors) # 输出: ['red', 'yellow', 'blue', 'purple', 'cyan', 'magenta', 'p', 'i', 'n', 'k', 1, 2, 3]

colors.remove("yellow") # 删除值 'yellow'
print(colors) # 输出: ['red', 'blue', 'purple', 'cyan', 'magenta', 'p', 'i', 'n', 'k', 1, 2, 3]

last_color = colors.pop() # 删除并返回 'magenta'
print(f"Removed color: {last_color}")
print(colors) # 输出: ['red', 'blue', 'purple', 'cyan', 'p', 'i', 'n', 'k', 1, 2]

常用的列表方法

除了上面提到的,列表还有许多非常有用的内置方法。

sort():对列表进行原地排序(会修改原列表)。

sorted() 函数:返回一个排序后的新列表,不修改原列表。

reverse():将列表中的元素原地反转。

len() 函数:返回列表的长度(元素个数)。

count():返回指定元素在列表中出现的次数。

index():返回指定元素在列表中首次出现的索引。

copy():返回列表的一个浅拷贝。

列表推导式 (List Comprehensions)/列表生成式

列表生成式是一种优雅且高效的创建列表的方式。它允许你用一行代码代替多行的 for 循环,使代码更具可读性和 Pythonic 风格。

它的基本结构如下:

1
new_list = [expression for item in iterable if condition]
我们可以将这个结构拆解成四个部分来理解: - expression (表达式):基于 item 计算得出的新列表中的元素。 - for item in iterable (循环):遍历一个可迭代对象,将每个元素赋值给 item。这是必须的部分。 - if condition (条件判断):一个可选的过滤器。只有当 condition 为 True 时,expression 的结果才会被添加到新列表中, 不过不能加 else。 - [] (方括号):表示我们正在创建一个列表。

为了更好地理解,我们来看几个从传统 for 循环演变到列表生成式的例子

1
2
3
4
5
6
7
8
9
# 传统的 for 循环方式
squares = []
for x in range(10):
squares.append(x**2)
print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 使用列表生成式
squares = [x**2 for x in range(10)]
print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
还可以在表达式中使用条件判断(if … else):
1
2
3
4
5
# 注意:if-else 结构在表达式部分,而不是在末尾
number_types = ['even' if x % 2 == 0 else 'odd' for x in range(10)]

print(number_types)
# 输出: ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
可见,在一个列表生成式中,for前面的if … else是表达式,而for后面的if是过滤条件,不能带else。

列表生成式的优点: - 代码简洁:将多行代码浓缩为一行,减少了代码的冗余。 - 可读性强:对于熟悉其语法的开发者来说,列表生成式能够更清晰地表达代码的意图。 - 性能更高:列表生成式通常比等效的 for 循环和 append 操作要快。这是因为 Python 解释器可以为其进行专门的优化,避免了在循环中重复调用 append 方法的开销。

除了列表生成式,Python 还提供了类似的字典生成式和集合生成式,它们的语法结构非常相似: {key_expr: val_expr for item in iterable} (字典生成式) {expr for item in iterable} (集合生成式)

元组 (Tuple)

元组是一个有序的不可变的集合,可以包含任意类型的对象。元组使用圆括号 () 来定义,元素之间用逗号分隔。