Python 列表(list):方法、切片、排序、append、元组与集合
列表(list)是 Python 中有序、可变的集合,用方括号书写,例如 [250, 1200, 99]:可以用 append 添加元素,也可以插入、删除、切片和排序。sort 原地排序并返回 None,而 sorted 返回一个新的已排序列表。
Python 中的列表(list)是一组有序的任意值,写在方括号中,并且可以修改:可以在末尾添加元素,在中间插入,删除,排序。它是语言中最常用的集合:文件的行、一个月的支出、API 的响应,几乎都从列表开始。下面完整讲解 python list:创建、方法、切片、排序、列表推导式、复制,最后是元组和集合。
什么是 Python 列表
列表按你设定的顺序保存元素,并通过从 0 开始的索引访问。同一个列表中可以放不同类型的值,不过实际中通常保存同类数据。
amounts = [250, 1200, 99]
print(amounts[0]) # 250 — 第一个元素
print(amounts[-1]) # 99 — 最后一个元素
amounts[1] = 1300 # 列表是可变的
print(len(amounts)) # 3 — 列表长度
列表的长度由函数 len() 返回。访问不存在的索引会得到 IndexError: list index out of range。
创建列表
empty = [] # 空列表
also_empty = list() # 用 list 函数创建,效果相同
nums = [1, 2, 3]
chars = list("abc") # ['a', 'b', 'c']
digits = list(range(5)) # [0, 1, 2, 3, 4]
zeros = [0] * 4 # [0, 0, 0, 0]
函数 list() 可以把任何可迭代对象转换为列表:字符串、range、集合、字典的键。
append 与其他列表方法
append 在列表末尾添加一个元素,是 Python 中最常用的方法之一。它原地修改列表,并返回 None。
amounts = [250, 1200]
amounts.append(450) # [250, 1200, 450]
amounts.extend([10, 20]) # [250, 1200, 450, 10, 20]
amounts.insert(0, 5) # [5, 250, 1200, 450, 10, 20]
amounts.remove(1200) # 删除第一个值为 1200 的元素
last = amounts.pop() # 20 — 删除并返回最后一个元素
常见错误:a.append([10, 20]) 只会添加一个元素,即嵌套的列表,而不是两个数字。要添加多个元素,应使用 extend。
| 方法 | 作用 |
|---|---|
append(x) | 在末尾添加 x |
extend(iter) | 添加序列中的所有元素 |
insert(i, x) | 在索引 i 之前插入 x |
remove(x) | 删除第一次出现的 x(不存在则 ValueError) |
pop(i=-1) | 删除并返回索引 i 处的元素 |
index(x) | 第一次出现的索引 |
count(x) | x 出现的次数 |
sort() | 原地排序 |
reverse() | 原地反转 |
copy() | 浅复制 |
clear() | 清空列表 |
按索引或整个范围删除元素也可以使用 del 语句:del a[0]、del a[1:3]。对列表很有用的内置函数有:len、sum、min、max、sorted、reversed、enumerate、zip。
Python 中的切片
切片按 a[start:stop:step] 的格式取出列表的一部分:从 start(包含)到 stop(不包含),步长为 step。每一部分都可以省略。切片总是返回一个新列表。
a = [0, 1, 2, 3, 4, 5]
print(a[1:4]) # [1, 2, 3]
print(a[:2]) # [0, 1] — 前两个
print(a[-2:]) # [4, 5] — 最后两个
print(a[::2]) # [0, 2, 4] — 每隔一个
print(a[::-1]) # [5, 4, 3, 2, 1, 0] — 反转
print(a[:]) # 整个列表的副本
与索引不同,切片超出列表范围不会报错:a[10:20] 只会返回 []。还可以给切片赋值来替换列表的一部分:a[1:3] = ["x", "y", "z"]。
字符串切片
切片对所有序列都适用,包括字符串和元组:
s = "Python 3.15"
print(s[:6]) # Python
print(s[-4:]) # 3.15
print(s[::-1]) # 51.3 nohtyP
字符串不能通过切片修改——字符串是不可变的,切片会创建一个新字符串。
列表排序:sort 与 sorted
这是新手最容易混淆的地方。sort 方法在列表内部重新排列元素,并返回 None。函数 sorted 不改动原列表,而是返回一个新的已排序列表。
amounts = [250, 1200, 99]
amounts.append(450)
print(sorted(amounts)) # [99, 250, 450, 1200] — 新副本
print(amounts) # [250, 1200, 99, 450] — 原列表不变
result = amounts.sort() # 原地排序
print(result, amounts) # None [99, 250, 450, 1200]
这就是经典的“为什么我得到 None”问题:a = a.sort() 会把列表覆盖成 None。应该写 a.sort(),或者 a = sorted(a)。
关键字 key 与逆序
两者都接受 key 和 reverse 参数。key 是一个函数,元素将根据它的结果进行比较。
words = ["coffee", "Taxi", "subscription"]
print(sorted(words, key=len)) # ['Taxi', 'coffee', 'subscription']
print(sorted(words, key=str.lower)) # 不区分大小写
print(sorted([3, 1, 2], reverse=True)) # [3, 2, 1]
expenses = [("餐饮", 650), ("电影", 120), ("打车", 300)]
expenses.sort(key=lambda e: e[1]) # 按金额排序
Python 的排序是稳定的:键相同的元素保持原来的相对顺序。另一个区别在于适用范围:sorted 可以用于任何序列(字符串、字典、集合),而 sort 只有列表才有。
反转列表
有三种方式,行为各不相同:
a.reverse()— 原地反转,返回None;a[::-1]— 生成一个新的反转列表;reversed(a)— 惰性迭代器,适合在循环中使用:for x in reversed(a):。
遍历列表
items = ["咖啡", "地铁", "电影"]
for item in items:
print(item)
for i, item in enumerate(items, start=1):
print(i, item) # 1 咖啡,2 地铁,3 电影
print("电影" in items) # True — 检查是否包含
不要在遍历列表的同时删除其中的元素,否则会漏掉一些元素。应该用列表推导式生成一个新列表,或者遍历副本 a[:]。
列表推导式(list comprehension)
列表推导式可以用一行代码构造新列表:表达式、循环以及可选的条件。
squares = [n * n for n in range(6)] # [0, 1, 4, 9, 16, 25]
big = [a for a in [250, 1200, 99] if a > 200] # [250, 1200]
names = [s.strip().title() for s in [" alice ", "bob"]] # ['Alice', 'Bob']
列表推导式通常比带 append 的循环更快,也更易读。但如果逻辑无法放进一行清晰的代码中,普通的循环更好。
列表的合并、相加与相减
a = [1, 2, 3]
b = [3, 4]
print(a + b) # [1, 2, 3, 3, 4] — 新列表
a += b # 相当于 a.extend(b)
print([*a, *b]) # 解包到新列表中
Python 中没有用 - 来做列表相减的运算符。要从一个列表中去掉另一个列表的元素,可以使用推导式:[x for x in a if x not in set(b)]。列表的交集最方便的方法是借助集合:set(a) & set(b)(这会丢失顺序和重复元素)。
嵌套列表与二维列表
列表的列表是保存表格或矩阵的简单方式:
matrix = [[1, 2, 3], [4, 5, 6]]
print(matrix[1][2]) # 6
grid = [[0] * 3 for _ in range(2)] # 正确
bad = [[0] * 3] * 2 # 陷阱:两个引用指向同一个列表
bad[0][0] = 9
print(bad) # [[9, 0, 0], [9, 0, 0]]
列表解包
first, second, third = [10, 20, 30]
head, *rest = [1, 2, 3, 4] # head=1, rest=[2, 3, 4]
print(*["a", "b"], sep=", ") # a, b — 不带括号打印列表元素
如果变量数量与列表长度不一致,会得到 ValueError——这时星号变量就能派上用场。
复制列表
b = a 并不会复制列表,而是给同一个对象再贴上一个标签:通过 b 做的修改在 a 中也能看到。独立的副本需要显式创建:a.copy()、list(a) 或 a[:]。对于嵌套数据,这还不够——内层列表依然共享,需要使用 copy.deepcopy(a)。
import copy
a = [[1, 2], [3]]
b = a.copy()
b[0].append(99)
print(a) # [[1, 2, 99], [3]] — 嵌套列表是共享的
c = copy.deepcopy(a) # 完全独立的副本
元组:不可变的列表
元组(tuple)与列表相似,但创建后不能修改。这向读者传达了一个明确的信号:这是一条由固定字段组成的记录,而不是可以增长的集合。元组很容易解包,函数通常正是用元组返回多个值。
expense = (250, "咖啡")
amount, item = expense
expense[0] = 300
# TypeError: 'tuple' object does not support item assignment
由不可变值组成的元组是可哈希的,因此可以用作字典的键。只有一个元素的元组要写逗号:(5,)。
集合:只保存唯一值
集合(set)只保存唯一的值,并且不记录顺序。它是去重以及检查“是否存在”的最快方法,还支持交集、并集和差集。
jan = {"餐饮", "打车", "电影"}
feb = {"餐饮", "订阅"}
print(jan & feb) # {'餐饮'}
print(feb - jan) # {'订阅'}
unique = list(dict.fromkeys([3, 1, 3, 2])) # [3, 1, 2] — 去重且保持顺序
empty = set() # {} 是空字典!
如何选择集合类型
| 任务 | 集合类型 |
|---|---|
| 需要顺序并且可以修改 | list |
| 固定的记录 | tuple |
| 按键查找 | dict |
| 唯一性,检查是否存在 | set |
| 不可变的设置 | frozendict(Python 3.15) |
x in list 会逐个比较元素,而 x in set 几乎是瞬间完成的。如果在循环中多次检查一个大列表中是否包含某值,把它转换为集合。
小结
Python 列表是有序、可变的集合:append 和 extend 用于添加,pop 和 remove 用于删除,切片 a[start:stop:step] 用于截取部分,sort 原地排序并返回 None,而 sorted 返回新列表。复制要显式进行;固定的记录使用元组,唯一的值使用集合。列表、元组、字典和集合在课程《Python 3.15:从新手到专家》中都有实践讲解。
常见问题
Python 列表和数组有什么区别?
Python 中没有其他语言意义上的内置数组,它的角色由列表承担,列表可以同时保存不同类型的值。紧凑的数值数组可以使用 array 模块或 NumPy 库。
如何查找列表中某个元素的索引?
方法 a.index(x) 返回第一次出现的索引,如果元素不存在则抛出 ValueError。因此调用前最好先检查 x in a。
如何在保持顺序的情况下去除列表中的重复项?
使用 list(dict.fromkeys(a)):字典的键是唯一的,并且保持插入顺序。list(set(a)) 也能去重,但不保留顺序。
如何把字符串列表合并为一个字符串?
使用字符串的 join 方法:", ".join(["a", "b", "c"]) 得到 "a, b, c"。所有元素必须是字符串,数字要先用 map(str, a) 转换。
列表中可以放不同类型的元素吗?
可以,一个列表可以同时包含数字、字符串、其他列表以及任何对象。但对这样的列表排序通常需要提供 key 参数,否则比较数字和字符串会引发 TypeError。