预计阅读时间:30 分钟
Python 推导式完全指南
一、推导式的本质:声明式编程的优雅
推导式(Comprehension)是 Python 最具特色的语法之一,它允许你用一行代码创建集合,而不是用多行循环。这不仅让代码更简洁,更重要的是它表达了你的意图,而不是实现细节。
1.1 从循环到推导式
# 传统方式:告诉计算机"如何做"
numbers = []
for i in range(10):
if i % 2 == 0:
numbers.append(i * i)
# 推导式:告诉计算机"想要什么"
numbers = [i * i for i in range(10) if i % 2 == 0]
print(f"传统方式: {numbers}")
print(f"推导式: {numbers}")
# 推导式的优势:
# 1. 代码更简洁(1行 vs 3行)
# 2. 意图更清晰(声明式 vs 命令式)
# 3. 执行效率更高(Python 内部优化)
1.2 推导式的性能优势
import timeit
# 性能对比
def loop_method():
result = []
for i in range(1000):
result.append(i * i)
return result
def comprehension_method():
return [i * i for i in range(1000)]
# 计时
loop_time = timeit.timeit(loop_method, number=10000)
comp_time = timeit.timeit(comprehension_method, number=10000)
print(f"循环方式: {loop_time:.4f}秒")
print(f"推导式: {comp_time:.4f}秒")
print(f"推导式快 {loop_time/comp_time:.2f}倍")
# 原因:推导式在 C 层面执行,避免了 Python 层面的循环和 append 调用
二、列表推导式
2.1 基础语法
# 基本语法:[expression for item in iterable]
# 1. 简单映射
numbers = [1, 2, 3, 4, 5]
squares = [x ** 2 for x in numbers]
print(f"平方: {squares}")
# 2. 字符串操作
names = ['alice', 'bob', 'charlie']
capitalized = [name.capitalize() for name in names]
print(f"首字母大写: {capitalized}")
# 3. 类型转换
mixed = ['1', '2', '3', '4', '5']
integers = [int(x) for x in mixed]
print(f"转换为整数: {integers}")
# 4. 调用函数
import math
values = [0, 30, 45, 60, 90]
sin_values = [math.sin(math.radians(x)) for x in values]
print(f"正弦值: {[f'{v:.2f}' for v in sin_values]}")
# 5. 多个可迭代对象
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
combined = [f"{x}{y}" for x in list1 for y in list2]
print(f"组合: {combined}")
2.2 带条件的推导式
# 语法:[expression for item in iterable if condition]
# 1. 过滤
numbers = range(20)
evens = [x for x in numbers if x % 2 == 0]
print(f"偶数: {evens}")
# 2. 复杂条件
words = ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig']
# 长度大于5且包含'a'的单词
filtered = [w.upper() for w in words if len(w) > 5 and 'a' in w]
print(f"过滤后: {filtered}")
# 3. if-else 在表达式中(注意位置!)
numbers = range(10)
# 错误:if-else 在条件位置
# [x if x % 2 == 0 else -x for x in numbers] # 正确
# [x for x in numbers if x % 2 == 0 else -x] # 错误!
# 正确:条件表达式在表达式部分
parity = ['偶数' if x % 2 == 0 else '奇数' for x in numbers]
print(f"奇偶判断: {parity}")
# 4. 多个条件(相当于 and)
numbers = range(30)
# 能被2和3整除的数
divisible_by_6 = [x for x in numbers if x % 2 == 0 if x % 3 == 0]
print(f"被6整除: {divisible_by_6}")
# 5. 使用条件表达式进行转换
grades = [85, 92, 78, 65, 95, 45]
letter_grades = ['A' if g >= 90 else 'B' if g >= 80 else 'C' if g >= 70 else 'D' if g >= 60 else 'F'
for g in grades]
print(f"等级: {letter_grades}")
2.3 嵌套列表推导式
# 1. 展平嵌套列表
nested = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in nested for num in row]
print(f"展平: {flattened}")
# 等价的双重循环
flattened_loop = []
for row in nested:
for num in row:
flattened_loop.append(num)
print(f"循环方式: {flattened_loop}")
# 2. 矩阵转置
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
print(f"转置矩阵: {transposed}")
# 更优雅的方式
transposed_zip = [list(row) for row in zip(*matrix)]
print(f"使用zip: {transposed_zip}")
# 3. 生成乘法表
multiplication_table = [[i * j for j in range(1, 10)] for i in range(1, 10)]
print("乘法表 (3x3):")
for row in multiplication_table[:3]:
print(f" {row[:3]}")
# 4. 处理三维列表
cube = [[[i+j+k for k in range(2)] for j in range(2)] for i in range(2)]
print(f"三维列表: {cube}")
2.4 实战案例
# 案例1:文本处理
def analyze_text(text):
"""分析文本,提取单词"""
# 转换为小写,分割,过滤空字符串,去重
words = [word.lower() for word in text.split() if word.strip()]
unique_words = list(set(words))
# 统计单词长度
word_lengths = [(word, len(word)) for word in unique_words]
return unique_words, word_lengths
text = "Python is awesome! Python is powerful! Python is fun!"
unique, lengths = analyze_text(text)
print(f"唯一单词: {unique}")
print(f"单词长度: {lengths}")
# 案例2:数据清洗
def clean_data(data):
"""清洗数据列表"""
return [
float(x.strip()) if isinstance(x, str) else float(x)
for x in data
if x is not None and str(x).strip() and str(x).strip() != 'N/A'
]
raw_data = ['1.5', '2.7', 'N/A', None, '3.14', '', ' 4.2 ']
cleaned = clean_data(raw_data)
print(f"清洗后数据: {cleaned}")
# 案例3:文件处理
def extract_log_errors(log_file):
"""从日志文件提取错误信息"""
with open(log_file, 'r') as f:
errors = [
line.strip()
for line in f
if 'ERROR' in line or 'WARNING' in line
]
return errors
# 创建测试日志
with open('test.log', 'w') as f:
f.write("INFO: Application started\n")
f.write("ERROR: Database connection failed\n")
f.write("WARNING: Low memory\n")
f.write("INFO: User logged in\n")
f.write("ERROR: File not found\n")
errors = extract_log_errors('test.log')
print(f"错误和警告: {errors}")
# 案例4:笛卡尔积(组合问题)
def generate_combinations():
"""生成所有可能的组合"""
colors = ['red', 'blue', 'green']
sizes = ['S', 'M', 'L']
styles = ['casual', 'formal']
# 所有组合
products = [
f"{color}-{size}-{style}"
for color in colors
for size in sizes
for style in styles
]
return products
combinations = generate_combinations()
print(f"总组合数: {len(combinations)}")
print(f"前5个组合: {combinations[:5]}")
# 案例5:解析嵌套数据结构
def parse_json_like_data(data):
"""解析类JSON的数据结构"""
# 假设数据结构:users -> [{name, age, emails}]
all_emails = [
email
for user in data.get('users', [])
for email in user.get('emails', [])
if '@' in email
]
# 按年龄段分组
age_groups = {
'young': [u['name'] for u in data.get('users', []) if u.get('age', 0) < 30],
'middle': [u['name'] for u in data.get('users', []) if 30 <= u.get('age', 0) < 50],
'senior': [u['name'] for u in data.get('users', []) if u.get('age', 0) >= 50]
}
return all_emails, age_groups
sample_data = {
'users': [
{'name': 'Alice', 'age': 25, 'emails': ['alice@work.com', 'alice@gmail.com']},
{'name': 'Bob', 'age': 35, 'emails': ['bob@work.com']},
{'name': 'Charlie', 'age': 55, 'emails': ['charlie@invalid', 'charlie@gmail.com']}
]
}
emails, groups = parse_json_like_data(sample_data)
print(f"所有有效邮箱: {emails}")
print(f"年龄分组: {groups}")
三、字典推导式
3.1 基础语法
# 语法:{key_expression: value_expression for item in iterable}
# 1. 从列表创建字典
names = ['Alice', 'Bob', 'Charlie']
name_lengths = {name: len(name) for name in names}
print(f"名字长度: {name_lengths}")
# 2. 从两个列表创建字典
keys = ['name', 'age', 'city']
values = ['Alice', 25, 'New York']
person = {k: v for k, v in zip(keys, values)}
print(f"个人信息: {person}")
# 3. 键值互换
original = {'a': 1, 'b': 2, 'c': 3}
swapped = {v: k for k, v in original.items()}
print(f"键值互换: {swapped}")
# 4. 从元组列表创建字典
items = [('apple', 5), ('banana', 3), ('orange', 8)]
inventory = {fruit: quantity for fruit, quantity in items}
print(f"库存: {inventory}")
# 5. 枚举创建字典
fruits = ['apple', 'banana', 'cherry']
indexed = {i: fruit for i, fruit in enumerate(fruits)}
print(f"索引字典: {indexed}")
3.2 带条件的字典推导式
# 1. 过滤
scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78, 'David': 95, 'Eve': 88}
high_scores = {name: score for name, score in scores.items() if score >= 90}
print(f"高分学生: {high_scores}")
# 2. 转换键或值
temperatures_c = {'Monday': 20, 'Tuesday': 25, 'Wednesday': 18, 'Thursday': 22, 'Friday': 24}
temperatures_f = {day: (c * 9/5 + 32) for day, c in temperatures_c.items()}
print(f"华氏温度: {temperatures_f}")
# 3. 复杂条件
users = {
'alice': {'age': 25, 'active': True},
'bob': {'age': 17, 'active': True},
'charlie': {'age': 30, 'active': False},
'david': {'age': 22, 'active': True}
}
# 筛选活跃的成年用户
adult_active = {
name: info
for name, info in users.items()
if info['active'] and info['age'] >= 18
}
print(f"活跃成年用户: {adult_active}")
# 4. 使用条件表达式转换值
products = {'apple': 1.2, 'banana': 0.8, 'orange': 1.5, 'grape': 2.0}
# 对价格低于1.0的商品打折
discounted = {
product: price * 0.9 if price < 1.0 else price
for product, price in products.items()
}
print(f"打折后价格: {discounted}")
3.3 嵌套字典推导式
# 1. 创建嵌套字典
matrix_dict = {
i: {j: i * j for j in range(1, 4)}
for i in range(1, 4)
}
print(f"嵌套字典: {matrix_dict}")
# 2. 展平嵌套字典
nested_dict = {
'group1': {'a': 1, 'b': 2},
'group2': {'c': 3, 'd': 4}
}
flattened = {
f"{group}_{key}": value
for group, inner_dict in nested_dict.items()
for key, value in inner_dict.items()
}
print(f"展平后的字典: {flattened}")
# 3. 转换嵌套结构
students = {
'Alice': {'math': 90, 'english': 85, 'science': 92},
'Bob': {'math': 78, 'english': 88, 'science': 82},
'Charlie': {'math': 95, 'english': 90, 'science': 88}
}
# 按科目重组
by_subject = {
subject: {student: scores[subject] for student, scores in students.items()}
for subject in ['math', 'english', 'science']
}
print(f"按科目分组: {by_subject}")
# 4. 计算平均值
averages = {
student: sum(scores.values()) / len(scores)
for student, scores in students.items()
}
print(f"平均分: {averages}")
3.4 字典推导式实战
# 案例1:词频统计
def word_frequency(text):
"""统计词频"""
words = text.lower().split()
return {
word: words.count(word)
for word in set(words)
}
text = "the quick brown fox jumps over the lazy dog the fox"
freq = word_frequency(text)
print(f"词频: {freq}")
# 案例2:数据聚合
def aggregate_sales(sales_data):
"""按产品聚合销售额"""
return {
product: sum(quantity * price for _, p, quantity, price in sales_data if p == product)
for product in set(p for _, p, _, _ in sales_data)
}
sales = [
('2024-01-01', 'apple', 10, 1.5),
('2024-01-01', 'banana', 5, 0.8),
('2024-01-02', 'apple', 8, 1.5),
('2024-01-02', 'orange', 12, 2.0),
('2024-01-03', 'banana', 15, 0.8)
]
total_sales = aggregate_sales(sales)
print(f"总销售额: {total_sales}")
# 案例3:配置管理
class Config:
"""配置管理器"""
@staticmethod
def load_from_env(prefix='APP_'):
"""从环境变量加载配置"""
import os
# 只加载指定前缀的环境变量
config = {
key[len(prefix):].lower(): value
for key, value in os.environ.items()
if key.startswith(prefix)
}
# 类型转换
typed_config = {
key: Config._convert_value(value)
for key, value in config.items()
}
return typed_config
@staticmethod
def _convert_value(value):
"""转换值类型"""
# 布尔值
if value.lower() in ('true', 'false'):
return value.lower() == 'true'
# 整数
try:
return int(value)
except ValueError:
pass
# 浮点数
try:
return float(value)
except ValueError:
pass
# 字符串
return value
# 模拟环境变量
import os
os.environ['APP_DEBUG'] = 'true'
os.environ['APP_PORT'] = '8080'
os.environ['APP_HOST'] = 'localhost'
os.environ['APP_TIMEOUT'] = '30.5'
config = Config.load_from_env()
print(f"应用配置: {config}")
# 案例4:缓存装饰器(使用字典推导式)
def memoize(func):
"""记忆化装饰器"""
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
"""斐波那契数列"""
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 计算并缓存
fib_values = {i: fibonacci(i) for i in range(10)}
print(f"斐波那契数列: {fib_values}")
四、集合推导式
4.1 基础用法
# 语法:{expression for item in iterable}
# 1. 创建集合
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_squares = {x**2 for x in numbers}
print(f"唯一平方数: {unique_squares}")
# 2. 去重
words = ['hello', 'world', 'hello', 'python', 'WORLD', 'Hello']
unique_words = {word.lower() for word in words}
print(f"唯一单词: {unique_words}")
# 3. 集合运算
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
# 找出两个集合中都存在的偶数
common_even = {x for x in set1 & set2 if x % 2 == 0}
print(f"共同偶数: {common_even}")
# 4. 从字符串创建字符集
text = "Hello, World!"
chars = {char.lower() for char in text if char.isalpha()}
print(f"字符集: {chars}")
4.2 集合推导式实战
# 案例1:找出两个列表的共同元素
list1 = [1, 2, 3, 4, 5, 6]
list2 = [4, 5, 6, 7, 8, 9]
common = {x for x in list1 if x in list2}
print(f"共同元素: {common}")
# 更高效的方式
common_fast = set(list1) & set(list2)
print(f"高效方式: {common_fast}")
# 案例2:文本分析
def analyze_vocabulary(texts):
"""分析多段文本的词汇"""
# 所有文本中的所有单词
all_words = {
word.lower()
for text in texts
for word in text.split()
if len(word) > 2 # 过滤短词
}
# 找出在所有文本中都出现的单词
text_word_sets = [
{word.lower() for word in text.split()}
for text in texts
]
common_words = set.intersection(*text_word_sets) if text_word_sets else set()
return all_words, common_words
texts = [
"Python is a great programming language",
"Python can be used for web development",
"Learning Python is fun and rewarding"
]
all_words, common_words = analyze_vocabulary(texts)
print(f"总词汇: {len(all_words)}")
print(f"共同词汇: {common_words}")
# 案例3:质数生成器(使用集合推导式)
def sieve_of_eratosthenes(n):
"""埃拉托斯特尼筛法(使用集合推导式)"""
# 创建2到n的集合
numbers = set(range(2, n+1))
# 筛除非质数
for i in range(2, int(n**0.5) + 1):
if i in numbers:
# 使用集合推导式删除倍数
numbers -= {j for j in range(i*2, n+1, i)}
return numbers
primes = sieve_of_eratosthenes(50)
print(f"50以内的质数: {sorted(primes)}")
五、生成器表达式
5.1 基础概念
# 生成器表达式:使用 () 而不是 []
# 语法:(expression for item in iterable)
# 1. 列表推导式 vs 生成器表达式
list_comp = [x**2 for x in range(1000000)] # 立即创建列表,占用内存
gen_expr = (x**2 for x in range(1000000)) # 惰性求值,不占用内存
import sys
print(f"列表推导式内存: {sys.getsizeof(list_comp):,} 字节")
print(f"生成器表达式内存: {sys.getsizeof(gen_expr):,} 字节")
# 2. 使用生成器表达式
squares = (x**2 for x in range(10))
print(f"生成器: {squares}")
print(f"值: {list(squares)}") # 消费生成器
print(f"再次消费: {list(squares)}") # 空列表(已耗尽)
# 3. 作为函数参数(可以省略括号)
total = sum(x**2 for x in range(100))
print(f"平方和: {total}")
# 4. 结合其他函数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 找出所有大于5的偶数
result = any(x > 5 and x % 2 == 0 for x in numbers)
print(f"是否存在大于5的偶数: {result}")
# 找出第一个满足条件的元素
first = next((x for x in numbers if x > 5 and x % 2 == 0), None)
print(f"第一个大于5的偶数: {first}")
5.2 生成器表达式的优势
# 案例1:处理大文件
def process_large_file(filename):
"""使用生成器表达式处理大文件"""
with open(filename, 'r') as f:
# 逐行处理,不占用大量内存
line_lengths = (len(line) for line in f)
total_chars = sum(line_lengths)
# 重新打开文件(生成器已耗尽)
f.seek(0)
# 统计包含特定单词的行数
python_lines = sum(1 for line in f if 'Python' in line)
return total_chars, python_lines
# 创建测试文件
with open('large_file.txt', 'w') as f:
for i in range(1000):
f.write(f"Line {i}: Python is awesome!\n" if i % 2 == 0 else f"Line {i}: Hello World\n")
chars, python_count = process_large_file('large_file.txt')
print(f"总字符数: {chars}")
print(f"包含Python的行数: {python_count}")
# 案例2:管道处理
def data_pipeline(data):
"""使用生成器表达式构建数据处理管道"""
# 步骤1:过滤
filtered = (x for x in data if x > 0)
# 步骤2:转换
transformed = (x * 2 for x in filtered)
# 步骤3:再次过滤
final = (x for x in transformed if x < 100)
return final
data = range(-10, 60)
result = list(data_pipeline(data))
print(f"管道处理结果: {result}")
# 案例3:内存对比
def memory_comparison():
"""比较列表和生成器的内存使用"""
import sys
n = 1000000
# 列表:一次性加载所有数据
list_data = [i * i for i in range(n)]
list_memory = sys.getsizeof(list_data)
# 生成器:惰性求值
gen_data = (i * i for i in range(n))
gen_memory = sys.getsizeof(gen_data)
print(f"列表内存: {list_memory:,} 字节")
print(f"生成器内存: {gen_memory:,} 字节")
print(f"内存节省: {(1 - gen_memory/list_memory) * 100:.1f}%")
memory_comparison()
六、高级技巧与最佳实践
6.1 推导式的可读性
# 1. 过长的推导式应该拆分为多行
# 不推荐
result = [x*y for x in range(10) for y in range(10) if x != y if x > 5 if y < 5]
# 推荐
result = [
x * y
for x in range(10)
for y in range(10)
if x != y
if x > 5
if y < 5
]
print(f"格式化后的结果: {result}")
# 2. 复杂的逻辑应该提取为函数
def is_valid_product(x, y):
"""判断乘积是否有效"""
return x != y and x > 5 and y < 5
result = [
x * y
for x in range(10)
for y in range(10)
if is_valid_product(x, y)
]
print(f"使用函数: {result}")
# 3. 嵌套推导式要考虑可读性
# 可读性较差
matrix = [[i*j for j in range(5)] for i in range(5)]
# 更清晰的版本
def create_row(i):
return [i * j for j in range(5)]
matrix = [create_row(i) for i in range(5)]
print(f"清晰版矩阵: {matrix}")
# 4. 使用 walrus 运算符 (Python 3.8+)
# 避免重复计算
import math
# 传统方式
radii = [1, 2, 3, 4, 5]
areas = [math.pi * r * r for r in radii if math.pi * r * r > 10]
# 使用 walrus 运算符
areas_optimized = [
area for r in radii
if (area := math.pi * r * r) > 10
]
print(f"优化后: {areas_optimized}")
6.2 性能优化技巧
# 1. 使用局部变量加速
def slow_comprehension(data):
"""慢速版本"""
return [x.upper() for x in data]
def fast_comprehension(data):
"""快速版本(使用局部变量)"""
upper = str.upper # 缓存方法引用
return [upper(x) for x in data]
# 测试
import timeit
test_data = ['hello'] * 1000
slow_time = timeit.timeit(lambda: slow_comprehension(test_data), number=10000)
fast_time = timeit.timeit(lambda: fast_comprehension(test_data), number=10000)
print(f"慢速版本: {slow_time:.4f}s")
print(f"快速版本: {fast_time:.4f}s")
print(f"速度提升: {slow_time/fast_time:.2f}倍")
# 2. 避免不必要的中间列表
# 低效:创建中间列表
def inefficient(data):
filtered = [x for x in data if x > 0] # 中间列表
squared = [x**2 for x in filtered] # 另一个列表
return sum(squared)
# 高效:使用生成器表达式
def efficient(data):
return sum(x**2 for x in data if x > 0)
data = range(-1000, 1000)
ineff_time = timeit.timeit(lambda: inefficient(data), number=1000)
eff_time = timeit.timeit(lambda: efficient(data), number=1000)
print(f"\n低效版本: {ineff_time:.4f}s")
print(f"高效版本: {eff_time:.4f}s")
# 3. 使用 set 进行成员检查
# 低效:在列表中查找
def find_in_list(data, targets):
return [x for x in data if x in targets]
# 高效:在集合中查找
def find_in_set(data, targets):
target_set = set(targets)
return [x for x in data if x in target_set]
data = list(range(10000))
targets = list(range(5000, 6000))
list_time = timeit.timeit(lambda: find_in_list(data, targets), number=100)
set_time = timeit.timeit(lambda: find_in_set(data, targets), number=100)
print(f"\n列表查找: {list_time:.4f}s")
print(f"集合查找: {set_time:.4f}s")
print(f"速度提升: {list_time/set_time:.2f}倍")
6.3 常见陷阱与注意事项
# 陷阱1:推导式中的变量泄漏(Python 2 的问题,Python 3 已修复)
# Python 3 中推导式有自己的作用域
x = 10
squares = [x**2 for x in range(5)]
print(f"外部 x: {x}") # 10,不受影响
# 陷阱2:在推导式中修改正在迭代的集合
# 错误:在迭代时修改列表
data = [1, 2, 3, 4, 5]
# filtered = [data.remove(x) for x in data if x % 2 == 0] # 错误!
# 正确:创建新列表
filtered = [x for x in data if x % 2 != 0]
print(f"过滤后: {filtered}")
# 陷阱3:嵌套推导式的执行顺序
# 理解执行顺序:从左到右,外层到内层
nested = [(x, y) for x in range(2) for y in range(2)]
print(f"嵌套推导式: {nested}")
# 等价于:
nested_loop = []
for x in range(2):
for y in range(2):
nested_loop.append((x, y))
print(f"等价循环: {nested_loop}")
# 陷阱4:在推导式中捕获循环变量(闭包问题)
# 错误:所有 lambda 都捕获最后的 i
funcs_error = [lambda: i for i in range(3)]
print(f"错误结果: {[f() for f in funcs_error]}") # [2, 2, 2]
# 正确:使用默认参数固定值
funcs_correct = [lambda x=i: x for i in range(3)]
print(f"正确结果: {[f() for f in funcs_correct]}") # [0, 1, 2]
# 陷阱5:生成器表达式只能使用一次
gen = (x**2 for x in range(3))
print(f"第一次: {list(gen)}")
print(f"第二次: {list(gen)}") # 空列表
# 陷阱6:在推导式中使用可变对象
# 注意:所有元素引用同一个列表
matrix_bad = [[0] * 3] * 3
matrix_bad[0][0] = 1
print(f"错误矩阵(共享引用): {matrix_bad}")
# 正确:使用推导式创建独立列表
matrix_good = [[0] * 3 for _ in range(3)]
matrix_good[0][0] = 1
print(f"正确矩阵: {matrix_good}")
七、总结与最佳实践
7.1 选择指南
"""
推导式选择指南:
1. 列表推导式 [x for x in iterable]
- 需要列表结果时
- 需要多次访问结果时
- 数据量不大时
2. 字典推导式 {k: v for k, v in iterable}
- 需要键值对映射时
- 转换或过滤字典时
3. 集合推导式 {x for x in iterable}
- 需要去重时
- 集合运算时
4. 生成器表达式 (x for x in iterable)
- 处理大数据时
- 只需要遍历一次时
- 作为函数参数时
- 内存受限时
5. 避免推导式的情况
- 逻辑过于复杂(超过3个条件或循环)
- 需要异常处理时
- 需要提前退出时
- 有副作用时(如打印、文件写入)
"""
7.2 实战模板
# 模板1:数据过滤和转换
def transform_data(data):
"""标准的数据转换模板"""
return [
process(item)
for item in data
if is_valid(item)
]
# 模板2:构建映射表
def build_lookup_table(items, key_func, value_func):
"""构建查找表"""
return {
key_func(item): value_func(item)
for item in items
}
# 模板3:数据聚合
def aggregate_by_key(data, key_func, value_func):
"""按键聚合数据"""
from collections import defaultdict
result = defaultdict(list)
for item in data:
result[key_func(item)].append(value_func(item))
return dict(result)
# 模板4:扁平化处理
def flatten(nested_list):
"""扁平化嵌套列表"""
return [
item
for sublist in nested_list
for item in sublist
]
# 使用示例
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
transformed = transform_data(data)
print(f"转换后: {transformed}")
items = ['apple', 'banana', 'cherry']
lookup = build_lookup_table(items, lambda x: x[0], len)
print(f"查找表: {lookup}")
nested = [[1, 2], [3, 4, 5], [6]]
flat = flatten(nested)
print(f"扁平化: {flat}")
7.3 最终建议
"""
推导式最佳实践总结:
1. 可读性优先
- 如果推导式超过一行,考虑格式化为多行
- 复杂逻辑提取为函数
- 嵌套不要超过2层
2. 性能考虑
- 小数据用推导式,大数据用生成器
- 避免在推导式中重复计算
- 使用局部变量缓存方法调用
3. 正确性保证
- 注意推导式的作用域(Python 3 中很安全)
- 生成器只能消费一次
- 注意可变对象的引用问题
4. 代码风格
- 保持推导式简洁
- 使用有意义的变量名
- 必要时添加注释
记住:推导式是工具,不是目的。
好的代码首先是可读的,其次才是简洁的。
"""
推导式是 Python 最优雅的特性之一,掌握它能让你的代码更加 Pythonic。但要记住,简洁不等于晦涩,可读性永远是第一位的。在合适的场景使用合适的推导式,你的代码将会既高效又优雅。
本文由 尚先生 原创,转载请注明出处。
评论
0