Python: 列表进阶与元组

上一课学了列表的基本操作,这一课来点更"Python 风格"的东西——列表推导式写一行顶五行的快感、元组这个"不可变的列表"什么时候用。学完这些,你写的代码会越来越像真正的 Python 程序员。


1. 列表排序进阶

第 10 课学了 sort()sorted() 的基本用法,但它们还可以接受一个 key 参数来指定"按什么规则排序"。

PYTHON
# 按字符串长度排序
words = ["Python", "Java", "JavaScript", "C", "Go"]
sorted_by_len = sorted(words, key=len)
print(sorted_by_len)          # ['C', 'Go', 'Java', 'Python', 'JavaScript']

# 按最后一个字符排序
words = ["banana", "apple", "cherry", "date"]
sorted_by_last = sorted(words, key=lambda w: w[-1])
print(sorted_by_last)         # ['banana', 'date', 'apple', 'cherry']

# 按元组中某个元素排序——后面会学
scores = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]
sorted_scores = sorted(scores, key=lambda s: s[1], reverse=True)
print(sorted_scores)          # [('Bob', 92), ('Alice', 85), ('Charlie', 78)]
💡 key 参数超级实用—— 你可以传任何接受一个参数并返回一个值的函数,sorted() 会用这个返回值来排序。上面的 lambda 是匿名函数,后面会细讲。

▶ 示例:排行榜生成(难度⭐⭐)

PYTHON
# 游戏排行榜——按分数降序排列
players = [
    ("玩家1", 3500),
    ("玩家2", 5200),
    ("玩家3", 2800),
    ("玩家4", 4100),
]

# 按分数降序
ranked = sorted(players, key=lambda p: p[1], reverse=True)

print("=== 排行榜 ===")
for i, (name, score) in enumerate(ranked, 1):
    print(f"第{i}名:{name} —— {score}分")
▶ 试一试

运行结果:

TEXT 📖 仅展示
=== 排行榜 ===
第1名:玩家2 —— 5200分
第2名:玩家4 —— 4100分
第3名:玩家1 —— 3500分
第4名:玩家3 —— 2800分


2. 列表推导式入门

列表推导式(List Comprehension)是 Python 最受欢迎的特性之一——用一行代码生成一个新列表。

(1) 基本语法

TEXT 📖 仅展示
[表达式 for 变量 in 可迭代对象]

(2) 传统写法 vs 推导式

PYTHON
# 生成 0~9 的平方——传统写法
squares = []
for i in range(10):
    squares.append(i ** 2)
print(squares)                # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 用列表推导式——一行搞定
squares = [i ** 2 for i in range(10)]
print(squares)                # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

(3) 带条件的推导式

PYTHON
# 筛选出偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [n for n in numbers if n % 2 == 0]
print(evens)                  # [2, 4, 6, 8, 10]

# 把字符串转成大写
words = ["hello", "world", "python"]
upper_words = [w.upper() for w in words]
print(upper_words)            # ['HELLO', 'WORLD', 'PYTHON']

# 筛选长度 >= 5 的单词
words = ["cat", "elephant", "dog", "giraffe", "ant"]
long_words = [w for w in words if len(w) >= 5]
print(long_words)             # ['elephant', 'giraffe']
💡 推导式虽然简洁,但不要滥用。 如果逻辑复杂(比如嵌套循环或多个条件),写成普通 for 循环更容易读懂。简洁 ≠ 可读。

▶ 示例:数据处理(难度⭐⭐)

PYTHON
# 原始数据——可能有空值和多余空白
raw_data = ["  Alice  ", "", "  Bob  ", "  Charlie  ", "", "  赵六  "]

# 用推导式一步完成:去空白 + 过滤空值
cleaned = [name.strip() for name in raw_data if name.strip()]
print(cleaned)                # ['Alice', 'Bob', 'Charlie', '赵六']

# 数值处理
temps_c = [0, 10, 20, 30, 40]
temps_f = [c * 9 / 5 + 32 for c in temps_c]
print(temps_f)                # [32.0, 50.0, 68.0, 86.0, 104.0]
▶ 试一试

输出:

TEXT 📖 仅展示
# 执行成功


3. 元组是什么

元组(tuple)用圆括号 () 定义,和列表很像,但有一个关键区别——元组不可变,创建后不能修改。

PYTHON
# 定义元组
point = (3, 5)
color = (255, 0, 0)
empty = ()
single = (42,)          # 注意:单元素元组必须有逗号!

print(point)            # (3, 5)
print(type(point))      # <class 'tuple'>

(1) 元组不可变

PYTHON
point = (3, 5)
# point[0] = 10   ← 报错!元组不能修改
print(point[0])         # 3——可以读取,不能修改

(2) 为什么需要元组

元组不可变的特点带来了两个好处:

1. 可以作为字典的键(列表不行,因为可变)

PYTHON
# 元组可以作为字典的键
locations = {
    (35.68, 139.76): "东京",
    (31.23, 121.47): "上海",
}
print(locations[(35.68, 139.76)])   # 东京

# 列表不能做键
# d = {[1, 2]: "error"}    ← 会报错!

2. 表示一组不该被修改的数据

PYTHON
# 坐标、颜色、配置等"不会变"的数据适合用元组
RGB_RED = (255, 0, 0)        # 红色值不应该被修改
DEFAULT_CONFIG = ("localhost", 8080, "admin")
💡 什么时候用元组、什么时候用列表? 一个简单的判断标准:数据需要修改就用列表,不需要修改就用元组。 函数返回多个值时通常用元组(下一节)。



4. 元组解包

元组一个非常实用的特性——解包(unpacking),把元组的元素直接赋值给多个变量:

PYTHON
point = (3, 5)
x, y = point               # 解包
print(x)                   # 3
print(y)                   # 5

# 交换变量——本质就是元组解包
a, b = 10, 20
a, b = b, a                # 右侧先构造元组 (20, 10),再解包赋值
print(a, b)                # 20 10

# 函数返回多个值
def get_min_max(numbers):
    return min(numbers), max(numbers)

result = get_min_max([3, 1, 4, 1, 5])
print(result)              # (1, 5)

low, high = get_min_max([3, 1, 4, 1, 5])
print(f"最小值:{low},最大值:{high}")   # 最小值:1,最大值:5

(1) 使用 _ 忽略不需要的值

PYTHON
data = ("Alice", 25, "北京", "工程师")
name, _, city, _ = data     # 用 _ 表示"我不关心这个"
print(f"{name}住在{city}")  # Alice住在北京

▶ 示例:坐标计算(难度⭐⭐)

PYTHON
# 定义两个点
p1 = (1, 2)
p2 = (4, 6)

# 解包计算距离
x1, y1 = p1
x2, y2 = p2

distance = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
print(f"两点距离:{distance:.2f}")     # 5.00

# 用枚举遍历带索引
fruits = ["苹果", "香蕉", "橘子"]
for i, fruit in enumerate(fruits, 1):
    print(f"{i}. {fruit}")
▶ 试一试

运行结果:

TEXT 📖 仅展示
两点距离:5.00
1. 苹果
2. 香蕉
3. 橘子


5. 列表与元组的选型

特点 列表 元组
可变 ✅ 可增删改 ❌ 不可变
速度 稍慢 稍快
内存 稍大 稍小
能做字典键
使用场景 需要频繁修改的数据 固定不变的数据
典型用途 购物车、待办列表、动态数据 坐标、颜色、函数返回值
💡 一个实用的习惯: 如果你不确定用哪个,先用列表。绝大多数场景下列表更灵活。等你发现某个数据确实不该被修改时,再改成元组。



6. 常见应用场景


❓ 常见问题

Q 列表推导式和普通的 for 循环哪个快?
A 列表推导式通常更快,因为它在 C 层面执行循环,而不是 Python 层面。但差距只在数据量很大时(几万条以上)才明显。日常写代码,优先选可读性好的写法,不用太纠结性能。
Q 单元素元组为什么必须加逗号?(42)(42,) 有什么区别?
A (42) 中的括号被 Python 解释为数学分组,不是元组——type((42)) 结果是 <class 'int'>(42,) 才是元组。所以单元素元组必须加逗号:(42,)
Q sorted()key 参数怎么用?能举一个实际例子吗?
A 最常见的场景是按对象的某个属性排序。比如按字符串长度:sorted(words, key=len)。按列表中元组的第二个元素:sorted(data, key=lambda x: x[1])。按字典的值(下一课):sorted(dict.items(), key=lambda x: x[1])。关键是掌握 key 接受一个"把每个元素映射成排序依据"的函数。

📖 小节


📝 作业

  1. 基础题(难度⭐):用列表推导式生成 1 到 20 之间所有能被 3 整除的数字的平方。提示[表达式 for n in range(...) if 条件]

  2. 进阶题(难度⭐⭐):给定一个名字列表 names = [" alice ", "BOB", " Charlie", " david "],用列表推导式一步完成:去掉首尾空格 + 首字母大写其余小写。提示strip() 去空白,title()capitalize() 改大小写。

  3. 挑战题(难度⭐⭐⭐):写一个函数 analyze_numbers(*args),接收任意多个数字,返回一个元组 (最大值, 最小值, 平均值, 大于平均值的个数)提示:用 *args 接收可变参数,用列表推导式统计大于平均值的个数。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏