Python 推导式

Python基础 2026-04-20 12
预计阅读时间: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
暂无评论,来发表第一条评论吧

发表评论

登录 后发表评论