# ✅ 用生成器表达式:数据量大,只需遍历 big_data = (x**2for x inrange(10000000)) for x in big_data: process(x) # 处理完就扔,不占内存
# ✅ 用生成器表达式:链式处理,中间结果不需要存 result = sum(x**2for x inrange(1000000) if x % 2 == 0)
字典推导式 & 集合推导式
列表有推导式,字典和集合也有类似的语法:
字典推导式 {k: v for ...}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# 把两个列表组合成字典 keys = ['a', 'b', 'c'] values = [1, 2, 3] d = {k: v for k, v inzip(keys, values)} print(d) # {'a': 1, 'b': 2, 'c': 3}
# 交换字典的键值(值必须可哈希) original = {'apple': 5, 'banana': 3} swapped = {v: k for k, v in original.items()} print(swapped) # {5: 'apple', 3: 'banana'}
# 过滤字典(只保留值大于10的项) scores = {'张三': 85, '李四': 55, '王五': 92} passed = {k: v for k, v in scores.items() if v >= 60} print(passed) # {'张三': 85, '王五': 92}
集合推导式 {x for ...}
1 2 3 4 5 6 7 8 9
# 提取字符串列表的长度集合(去重) words = ["apple", "banana", "cherry", "date"] lengths = {len(w) for w in words} print(lengths) # {4, 5, 6}(去重后的长度)
# 找出所有包含字母'a'的单词的首字母 words = ["apple", "banana", "cherry", "date", "apricot"] first_chars = {w[0] for w in words if'a'in w} print(first_chars) # {'a', 'b', 'd'}
⚠️ 什么时候不该用列表推导式?
列表推导式很酷,但不是万能的。以下情况建议用普通循环:
1. 逻辑太复杂(超过2个条件或嵌套太深)
1 2 3 4 5 6 7 8 9
# ❌ 太难读懂了 result = [y for x in data for y in x if y > 0if y % 2 == 0]
# ✅ 用普通循环更清晰 result = [] for x in data: for y in x: if y > 0and y % 2 == 0: result.append(y)
2. 需要打印调试信息
1 2 3 4 5 6 7 8 9
# ❌ 推导式里没法print result = [x*2for x in data] # 中间过程看不见
# ✅ 用循环可以调试 result = [] for x in data: doubled = x * 2 print(f"{x} -> {doubled}") # 看中间结果 result.append(doubled)
3. 需要异常处理
1 2 3 4 5 6 7 8 9 10
# ❌ 推导式里不好处理异常 result = [int(x) for x in strings] # 如果x不能转int会崩溃
# ✅ 用循环可以try-except result = [] for x in strings: try: result.append(int(x)) except ValueError: result.append(0) # 给个默认值
4. 需要break/continue控制流程
1 2 3 4 5 6 7 8 9
# ❌ 推导式不支持break first_positive = [x for x in data if x > 0][0] # 会遍历全部
# ✅ 用循环找到就停 first_positive = None for x in data: if x > 0: first_positive = x break# 找到了,不继续了
原则:可读性 > 简洁性。 如果推导式让人看不懂,就用普通循环。
常见错误与避坑指南
错误1:忘记方括号
1 2 3 4 5
# ❌ 错的——这创建的是生成器,不是列表 squares = n ** 2for n in numbers
# ✅ 对的 squares = [n ** 2for n in numbers]
错误2:变量名冲突(遮蔽外部变量)
1 2 3 4 5 6 7 8 9
x = 100 data = [1, 2, 3]
# ⚠️ 推导式里的x会暂时覆盖外面的x result = [x * 2for x in data] print(x) # 100(Python 3.x里推导式有自己的作用域,不受影响)
# 但为了代码清晰,建议避免同名 result = [item * 2for item in data] # 用不同的名字
错误3:在推导式里修改正在遍历的列表
1 2 3 4 5 6 7
# ❌ 危险!不要在遍历列表时修改它 numbers = [1, 2, 3, 4, 5] [n for n in numbers if numbers.remove(n)] # 结果不可预测!
# ✅ 正确做法:创建新列表 numbers = [1, 2, 3, 4, 5] evens = [n for n in numbers if n % 2 == 0] # 筛选偶数到新列表
错误4:过度追求一行代码
1 2 3 4 5 6 7 8 9
# ❌ 为了用推导式而推导式,可读性极差 result = [[matrix[j][i] for j inrange(len(matrix))] for i inrange(len(matrix[0]))]
# ✅ 拆成函数,加注释 deftranspose(matrix): """转置矩阵:行变列,列变行""" rows = len(matrix) cols = len(matrix[0]) return [[matrix[j][i] for j inrange(rows)] for i inrange(cols)]
实战案例:数据处理中的列表推导式
案例1:清洗用户输入数据
1 2 3 4 5 6
# 用户输入(可能包含空值、前后空格、大小写不一致) raw_inputs = [" Alice ", "BOB", "", " Charlie", None, " david "]
# 清洗:去空值、去空格、统一小写 cleaned = [name.strip().lower() for name in raw_inputs if name] print(cleaned) # ['alice', 'bob', 'charlie', 'david']
# 获取当前目录下所有.py文件(不包括test_开头和__开头的) py_files = [ f for f in os.listdir('.') if f.endswith('.py') andnot f.startswith('test_') andnot f.startswith('__') ]
# 读取所有文件内容 contents = [] for filename in py_files: withopen(filename, encoding='utf-8') as f: contents.append({ "filename": filename, "lines": len(f.readlines()), "size": os.path.getsize(filename) })
# 筛选大文件(超过100行) large_files = [c for c in contents if c["lines"] > 100]