Python列表推导式:一行代码搞定复杂循环
Python列表推导式:一行代码搞定复杂循环
一、导语
刚学Python时,你是不是也写过这样的代码——先创建一个空列表,然后写一个for循环,再一行一行往里面append数据?这段代码通常要占四五行,每次写都觉得很啰嗦。其实Python早就为我们准备了一个优雅的替代方案:列表推导式(List Comprehension)。
列表推导式是Python最受欢迎的特性之一。它可以把多行的循环+条件逻辑压缩成一行,代码不仅更短,读起来也更接近"人类语言"。本文带你从入门到进阶,彻底掌握这个利器。
二、基础语法:从循环到推导式
先看一个最简单的场景:生成1到10的平方数列表。
传统写法(3行):
squares = []
for i in range(1, 11):
squares.append(i ** 2)
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
列表推导式(1行):
squares = [i ** 2 for i in range(1, 11)]
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
语法拆解一下:[表达式 for 变量 in 可迭代对象]。
for i in range(1, 11)— 和普通循环的for一样,依次取出每个元素i ** 2— 对每个元素执行的表达式,结果直接放入新列表- 外面用
[]包起来,表示我们要的是一个列表
把这个结构记牢,后面所有变体都是在这个基础上的扩展。
三、加上条件过滤:if的妙用
现实场景中,我们经常需要筛选数据。比如从一堆数字里挑出偶数再求平方。
传统写法:
even_squares = []
for i in range(1, 21):
if i % 2 == 0:
even_squares.append(i ** 2)
列表推导式:
even_squares = [i ** 2 for i in range(1, 21) if i % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
语法变为:[表达式 for 变量 in 可迭代对象 if 条件]。
注意if写在for的后面,而不是表达式前面。这恰好符合我们阅读的顺序——“从1到20里取出i,如果i是偶数,就计算i的平方”。
四、if-else:条件表达式放前面
如果筛选还不够,需要对不同情况做不同处理,就用if-else。但要记住一个重要区别:if-else写在表达式位置,if(无else)写在循环后面。
# 偶数求平方,奇数保持不变
result = [i ** 2 if i % 2 == 0 else i for i in range(1, 11)]
print(result) # [1, 4, 3, 16, 5, 36, 7, 64, 9, 100]
结构是:[结果A if 条件 else 结果B for i in ...]。这是Python的三元表达式嵌入到了推导式中。
对比记忆法:
| 场景 | 写法 | 位置 |
|---|---|---|
| 只要符合条件的 | if 条件 |
for 后面 |
| 符合条件的做A,否则做B | A if 条件 else B |
for 前面(表达式位置) |
五、嵌套循环:多维数据的处理利器
遇到二维列表(矩阵)时,列表推导式同样能大显身手。
展平二维列表:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# 传统写法
flat = []
for row in matrix:
for num in row:
flat.append(num)
# 推导式:for的顺序和传统嵌套一致
flat = [num for row in matrix for num in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
注意for的书写顺序:外层循环在前,内层循环在后,这和普通嵌套循环的书写顺序完全一致,非常好记。
再加条件过滤:
# 只提取大于5的元素
flat_big = [num for row in matrix for num in row if num > 5]
print(flat_big) # [6, 7, 8, 9]
六、实战场景:五个工作中常用的例子
6.1 清洗字符串列表
names = [" Alice ", "BOB", " Charlie ", "david"]
clean = [name.strip().title() for name in names]
print(clean) # ['Alice', 'Bob', 'Charlie', 'David']
6.2 筛选有效邮箱
emails = ["alice@qq.com", "invalid", "bob@163.com", "not-an-email", "charlie@gmail.com"]
valid = [e for e in emails if "@" in e and "." in e.split("@")[-1]]
print(valid) # ['alice@qq.com', 'bob@163.com', 'charlie@gmail.com']
6.3 字典列表提取字段
users = [
{"name": "张三", "age": 28, "city": "北京"},
{"name": "李四", "age": 35, "city": "上海"},
{"name": "王五", "age": 22, "city": "深圳"},
]
names = [u["name"] for u in users]
print(names) # ['张三', '李四', '王五']
# 30岁以上用户的城市
cities = [u["city"] for u in users if u["age"] > 30]
print(cities) # ['上海']
6.4 文件路径批量处理
import os
# 获取当前目录下所有.py文件的绝对路径
py_files = [
os.path.abspath(f)
for f in os.listdir(".")
if f.endswith(".py")
]
6.5 生成笛卡尔积
colors = ["红", "蓝", "绿"]
sizes = ["S", "M", "L"]
combinations = [f"{c}-{s}" for c in colors for s in sizes]
print(combinations)
# ['红-S', '红-M', '红-L', '蓝-S', '蓝-M', '蓝-L', '绿-S', '绿-M', '绿-L']
七、不止列表:字典推导式与集合推导式
学会了列表推导式,另外两种推导式就是换一对括号的事。
字典推导式:
# 把列表转成字典:名字→长度
words = ["python", "java", "golang"]
word_len = {w: len(w) for w in words}
print(word_len) # {'python': 6, 'java': 4, 'golang': 6}
# 键值互换
d = {"a": 1, "b": 2, "c": 3}
reversed_d = {v: k for k, v in d.items()}
print(reversed_d) # {1: 'a', 2: 'b', 3: 'c'}
集合推导式:
# 获取字符串中所有不重复的字母
text = "hello world"
unique_chars = {c for c in text if c != " "}
print(unique_chars) # {'d', 'e', 'h', 'l', 'o', 'r', 'w'}
八、注意事项:推导式不是万能药
列表推导式虽好,但过度使用会让代码变得难以阅读:
# 反面教材:嵌套三层还带条件,读起来很痛苦
result = [x * y for x in range(10) if x % 2 == 0 for y in range(10) if y % 3 == 0]
使用原则:
- 两层嵌套是上限:超过两层,老老实实用传统
for循环 - 单个推导式不超过一行:如果一行写不完(超过约80字符),拆成多行或用普通循环
- 复杂逻辑拆出来:如果表达式本身就很复杂,先定义成函数,再在推导式中调用
# 拆成函数,推导式就清晰了
def normalize(s):
return s.strip().lower().replace("-", "_")
fields = [" User-Name ", "Email-Address ", " Phone-Number"]
result = [normalize(f) for f in fields]
print(result) # ['user_name', 'email_address', 'phone_number']
九、总结
列表推导式是Python中"少即是多"哲学的典型体现。核心要点回顾:
| 要素 | 说明 |
|---|---|
| 基本语法 | [表达式 for 变量 in 可迭代对象] |
| 条件筛选 | [表达式 for 变量 in 可迭代对象 if 条件] |
| 条件分支 | [A if 条件 else B for 变量 in 可迭代对象] |
| 嵌套循环 | [表达式 for 外层 in 容器1 for 内层 in 容器2] |
| 字典推导 | {键: 值 for ... in ...} |
| 集合推导 | {元素 for ... in ...} |
掌握了列表推导式,你会发现很多原本需要五六行的循环逻辑,一行就能优雅地解决。代码更简洁,也更Pythonic。下次写循环前,不妨先想想:能不能用推导式搞定?
更多推荐


所有评论(0)