第72集:字典推导式

学习目标

  1. 理解字典推导式的概念和优势
  2. 掌握基本字典推导式的语法
  3. 学会使用条件表达式过滤字典
  4. 了解嵌套字典推导式的使用
  5. 掌握字典推导式与普通循环的转换

字典推导式概念

什么是字典推导式

字典推导式(Dictionary Comprehension)是Python中创建字典的简洁语法,它允许我们通过一个表达式和迭代器来快速生成字典。与列表推导式类似,字典推导式更加简洁、易读且通常性能更好。

字典推导式的优势

  • 代码简洁:一行代码替代多行循环
  • 性能更好:比传统for循环执行更快
  • 可读性强:意图明确,易于理解
  • 灵活性高:支持多种数据转换和过滤操作

基本字典推导式

基本语法结构

# 基本语法
{key_expression: value_expression for item in iterable}

# 传统for循环方式
result = {}
for item in iterable:
    result[key_expression] = value_expression

基本示例

# 1. 从列表创建字典
names = ["Alice", "Bob", "Charlie"]
name_length_dict = {name: len(name) for name in names}
print(f"姓名长度字典: {name_length_dict}")
# 输出: 姓名长度字典: {'Alice': 5, 'Bob': 3, 'Charlie': 7}

# 2. 创建数字平方字典
squares_dict = {x: x**2 for x in range(6)}
print(f"平方数字典: {squares_dict}")
# 输出: 平方数字典: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 3. 从两个列表创建字典
keys = ["name", "age", "city"]
values = ["张三", 25, "北京"]
person_dict = {k: v for k, v in zip(keys, values)}
print(f"个人信息字典: {person_dict}")
# 输出: 个人信息字典: {'name': '张三', 'age': 25, 'city': '北京'}

# 4. 创建字母ASCII码字典
ascii_dict = {char: ord(char) for char in "ABCDE"}
print(f"字母ASCII码: {ascii_dict}")
# 输出: 字母ASCII码: {'A': 65, 'B': 66, 'C': 67, 'D': 68, 'E': 69}

# 5. 创建月份天数字典
months = ["一月", "二月", "三月", "四月", "五月", "六月"]
days = [31, 28, 31, 30, 31, 30]
month_days = {month: day for month, day in zip(months, days)}
print(f"月份天数: {month_days}")
# 输出: 月份天数: {'一月': 31, '二月': 28, '三月': 31, '四月': 30, '五月': 31, '六月': 30}

使用函数和复杂表达式

# 1. 使用数学函数
import math
angles = [0, 30, 45, 60, 90]
trig_dict = {
    angle: {
        "sin": round(math.sin(math.radians(angle)), 4),
        "cos": round(math.cos(math.radians(angle)), 4)
    }
    for angle in angles
}
print(f"三角函数字典: {trig_dict}")
# 输出: 三角函数字典: {0: {'sin': 0.0, 'cos': 1.0}, 30: {'sin': 0.5, 'cos': 0.866}, ...}

# 2. 处理字符串列表
words = ["hello", "world", "python"]
word_info = {
    word: {
        "length": len(word),
        "uppercase": word.upper(),
        "reversed": word[::-1]
    }
    for word in words
}
print(f"单词信息字典: {word_info}")
# 输出: 单词信息字典: {'hello': {'length': 5, 'uppercase': 'HELLO', 'reversed': 'olleh'}, ...}

# 3. 从字典创建新字典
original_dict = {
    "name": "张三",
    "age": 25,
    "score": 85,
    "city": "北京"
}
new_dict = {k: v for k, v in original_dict.items()}
print(f"复制字典: {new_dict}")
# 输出: 复制字典: {'name': '张三', 'age': 25, 'score': 85, 'city': '北京'}

# 4. 复杂计算
temperatures = [0, 10, 20, 30, 40]
temp_conversion = {
    "摄氏度": temp,
    "华氏度": temp * 9/5 + 32,
    "开尔文": temp + 273.15
}
for temp in temperatures:
    print(f"{temp}°C = {temp * 9/5 + 32:.1f}°F = {temp + 273.15:.1f}K")

带条件的字典推导式

基本条件语法

# 条件筛选语法
{key_expression: value_expression for item in iterable if condition}

# 传统for循环方式
result = {}
for item in iterable:
    if condition:
        result[key_expression] = value_expression

条件筛选示例

# 1. 筛选偶数及其平方
numbers = range(1, 21)
even_squares = {num: num**2 for num in numbers if num % 2 == 0}
print(f"偶数及其平方: {even_squares}")
# 输出: 偶数及其平方: {2: 4, 4: 16, 6: 36, 8: 64, 10: 100, 12: 144, 14: 196, 16: 256, 18: 324, 20: 400}

# 2. 筛选特定长度的字符串
words = ["apple", "banana", "cherry", "date", "fig", "grape"]
short_words_dict = {word: len(word) for word in words if len(word) <= 4}
print(f"短单词字典: {short_words_dict}")
# 输出: 短单词字典: {'date': 4, 'fig': 3}

# 3. 筛选字典中的特定项
original_dict = {
    "name": "张三",
    "age": 25,
    "score": 85,
    "city": "北京",
    "grade": "A"
}
filtered_dict = {k: v for k, v in original_dict.items() if isinstance(v, (int, float))}
print(f"数值类型字典: {filtered_dict}")
# 输出: 数值类型字典: {'age': 25, 'score': 85}

# 4. 处理文件扩展名
files = ["report.pdf", "data.csv", "image.jpg", "document.docx", "presentation.pptx"]
image_dict = {file: file.split('.')[-1] for file in files if file.endswith(('.jpg', '.jpeg', '.png'))}
print(f"图片文件字典: {image_dict}")
# 输出: 图片文件字典: {'image.jpg': 'jpg'}

使用复杂条件

# 1. 多条件筛选
numbers = range(1, 31)
filtered_dict = {
    num: num**2 
    for num in numbers 
    if num % 2 == 0 and num % 3 == 0
}
print(f"能被2和3整除的数及其平方: {filtered_dict}")
# 输出: 能被2和3整除的数及其平方: {6: 36, 12: 144, 18: 324, 24: 576, 30: 900}

# 2. 字典条件筛选
products = {
    "Laptop": {"price": 1200, "category": "Electronics"},
    "Book": {"price": 20, "category": "Education"},
    "Headphones": {"price": 80, "category": "Electronics"},
    "Pen": {"price": 2, "category": "Office"},
    "Mouse": {"price": 15, "category": "Electronics"}
}

# 筛选电子产品且价格大于50的
expensive_electronics = {
    name: info 
    for name, info in products.items() 
    if info["category"] == "Electronics" and info["price"] > 50
}
print(f"高价电子产品字典: {expensive_electronics}")
# 输出: 高价电子产品字典: {'Laptop': {'price': 1200, 'category': 'Electronics'}, 'Headphones': {'price': 80, 'category': 'Electronics'}}

# 3. 使用函数作为条件
def is_prime(n):
    """检查是否为质数"""
    if n < 2:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

numbers = range(2, 31)
prime_dict = {num: num**2 for num in numbers if is_prime(num)}
print(f"质数及其平方: {prime_dict}")
# 输出: 质数及其平方: {2: 4, 3: 9, 5: 25, 7: 49, 11: 121, 13: 169, 17: 289, 19: 361, 23: 529, 29: 841}

# 4. 文本处理条件
sentences = [
    "Python is powerful",
    "List comprehensions are useful",
    "Code should be readable",
    "Programming is fun"
]

# 筛选包含特定单词的句子
python_sentences = {
    i: sentence 
    for i, sentence in enumerate(sentences) 
    if "python" in sentence.lower()
}
print(f"包含Python的句子: {python_sentences}")
# 输出: 包含Python的句子: {0: 'Python is powerful'}

字典推导式的高级用法

条件表达式与字典推导式

# 1. 根据条件生成不同值
numbers = range(-5, 6)
absolute_dict = {num: num if num >= 0 else -num for num in numbers}
print(f"绝对值字典: {absolute_dict}")
# 输出: 绝对值字典: {-5: 5, -4: 4, -3: 3, -2: 2, -1: 1, 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}

# 2. 分类标签
scores = [95, 67, 82, 45, 73, 88, 52]
grade_dict = {
    i: {
        "score": score,
        "grade": "优秀" if score >= 85 
        else "良好" if score >= 70 
        else "及格" if score >= 60 
        else "不及格"
    }
    for i, score in enumerate(scores)
}

print("成绩等级字典:")
for idx, info in grade_dict.items():
    print(f"  学生{idx+1}: {info['score']}分 - {info['grade']}")
# 输出:
# 成绩等级字典:
#   学生1: 95分 - 优秀
#   学生2: 67分 - 及格
#   学生3: 82分 - 良好
#   学生4: 45分 - 不及格
#   学生5: 73分 - 良好
#   学生6: 88分 - 优秀
#   学生7: 52分 - 不及格

# 3. 处理边界情况
numbers = [1, 2, 0, -1, -2, 3, -3]
safe_division_dict = {
    num: 1/num if num != 0 else "undefined" 
    for num in numbers
}
print(f"安全除法字典: {safe_division_dict}")
# 输出: 安全除法字典: {1: 1.0, 2: 0.5, 0: 'undefined', -1: -1.0, -2: -0.5, 3: 0.3333333333333333, -3: -0.3333333333333333}

# 4. 字符串处理
words = ["", "hello", "world", "", "python", ""]
processed_words_dict = {
    i: word.upper() if word else "EMPTY" 
    for i, word in enumerate(words)
}
print(f"处理后的单词字典: {processed_words_dict}")
# 输出: 处理后的单词字典: {0: 'EMPTY', 1: 'HELLO', 2: 'WORLD', 3: 'EMPTY', 4: 'PYTHON', 5: 'EMPTY'}

字典键值转换

# 1. 交换键和值
original_dict = {"a": 1, "b": 2, "c": 3}
swapped_dict = {v: k for k, v in original_dict.items()}
print(f"交换键值: {swapped_dict}")
# 输出: 交换键值: {1: 'a', 2: 'b', 3: 'c'}

# 2. 修改键名
original_dict = {
    "first_name": "张",
    "last_name": "三",
    "age": 25
}
renamed_dict = {
    "名" if k == "first_name" else "姓" if k == "last_name" else "年龄": v
    for k, v in original_dict.items()
}
print(f"修改键名: {renamed_dict}")
# 输出: 修改键名: {'名': '张', '姓': '三', '年龄': 25}

# 3. 修改值
original_dict = {
    "price1": 100,
    "price2": 200,
    "price3": 300
}
modified_dict = {
    k: v * 1.1 for k, v in original_dict.items()
}
print(f"增加10%: {modified_dict}")
# 输出: 增加10%: {'price1': 110.0, 'price2': 220.0, 'price3': 330.0}

# 4. 同时修改键和值
original_dict = {
    "item1": 10,
    "item2": 20,
    "item3": 30
}
transformed_dict = {
    k.upper(): v * 2 for k, v in original_dict.items()
}
print(f"转换键和值: {transformed_dict}")
# 输出: 转换键和值: {'ITEM1': 20, 'ITEM2': 40, 'ITEM3': 60}

字典推导式的应用案例

案例1:数据转换

# 1. 数据清洗
raw_data = {
    "name": "  张三  ",
    "age": "  25  ",
    "city": "  北京  ",
    "score": "  85  "
}

# 清洗数据:去除空格,转换类型
cleaned_data = {
    k: v.strip() if isinstance(v, str) else v
    for k, v in raw_data.items()
}

# 转换数值类型
cleaned_data["age"] = int(cleaned_data["age"])
cleaned_data["score"] = int(cleaned_data["score"])

print(f"清洗后的数据: {cleaned_data}")
# 输出: 清洗后的数据: {'name': '张三', 'age': 25, 'city': '北京', 'score': 85}

# 2. 数据聚合
students = [
    {"name": "张三", "subject": "数学", "score": 85},
    {"name": "张三", "subject": "英语", "score": 90},
    {"name": "李四", "subject": "数学", "score": 78},
    {"name": "李四", "subject": "英语", "score": 82},
    {"name": "王五", "subject": "数学", "score": 92},
    {"name": "王五", "subject": "英语", "score": 88}
]

# 按学生聚合成绩
student_scores = {}
for student in students:
    name = student["name"]
    if name not in student_scores:
        student_scores[name] = []
    student_scores[name].append(student["score"])

# 计算平均分
average_scores = {
    name: sum(scores) / len(scores)
    for name, scores in student_scores.items()
}

print(f"学生平均分: {average_scores}")
# 输出: 学生平均分: {'张三': 87.5, '李四': 80.0, '王五': 90.0}

案例2:文本处理

# 1. 词频统计
text = "Python is great. Python is popular. Python is powerful."
words = [word.strip(". ").lower() for word in text.split()]

word_count = {}
for word in words:
    word_count[word] = word_count.get(word, 0) + 1

print(f"词频统计: {word_count}")
# 输出: 词频统计: {'python': 3, 'is': 3, 'great': 1, 'popular': 1, 'powerful': 1}

# 2. 字符统计
sentence = "Hello World!"
char_count = {
    char: sentence.lower().count(char)
    for char in set(sentence.lower())
    if char.isalpha()
}

print(f"字符统计: {char_count}")
# 输出: 字符统计: {'h': 1, 'e': 1, 'l': 3, 'o': 2, 'w': 1, 'r': 1, 'd': 1}

# 3. 首字母统计
words = ["apple", "banana", "cherry", "apricot", "blueberry", "coconut"]
first_letter_count = {}

for word in words:
    first_letter = word[0].upper()
    first_letter_count[first_letter] = first_letter_count.get(first_letter, 0) + 1

print(f"首字母统计: {first_letter_count}")
# 输出: 首字母统计: {'A': 2, 'B': 2, 'C': 2}

案例3:配置管理

# 1. 配置转换
config = {
    "database_host": "localhost",
    "database_port": "5432",
    "database_name": "mydb",
    "cache_enabled": "true",
    "cache_ttl": "3600",
    "log_level": "INFO"
}

# 转换配置类型
typed_config = {
    k: int(v) if k.endswith("_port") or k.endswith("_ttl")
    else v.lower() == "true" if k.endswith("_enabled")
    else v
    for k, v in config.items()
}

print(f"类型化配置: {typed_config}")
# 输出: 类型化配置: {'database_host': 'localhost', 'database_port': 5432, 'database_name': 'mydb', 'cache_enabled': True, 'cache_ttl': 3600, 'log_level': 'INFO'}

# 2. 配置分组
grouped_config = {}
for k, v in config.items():
    prefix = k.split("_")[0]
    if prefix not in grouped_config:
        grouped_config[prefix] = {}
    grouped_config[prefix][k] = v

print(f"分组配置: {grouped_config}")
# 输出: 分组配置: {'database': {'database_host': 'localhost', 'database_port': '5432', 'database_name': 'mydb'}, 'cache': {'cache_enabled': 'true', 'cache_ttl': '3600'}, 'log': {'log_level': 'INFO'}}

字典推导式与普通循环的转换

从循环转换为推导式

# 1. 简单for循环转换
# 传统方式
squares_traditional = {}
for i in range(10):
    squares_traditional[i] = i ** 2

# 字典推导式
squares_comprehension = {i: i ** 2 for i in range(10)}

print(f"传统方式: {squares_traditional}")
print(f"推导式方式: {squares_comprehension}")
# 输出:
# 传统方式: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
# 推导式方式: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

# 2. 带条件的for循环转换
# 传统方式
even_numbers_traditional = {}
for i in range(1, 21):
    if i % 2 == 0:
        even_numbers_traditional[i] = i ** 2

# 字典推导式
even_numbers_comprehension = {i: i ** 2 for i in range(1, 21) if i % 2 == 0}

print(f"传统方式: {even_numbers_traditional}")
print(f"推导式方式: {even_numbers_comprehension}")
# 输出:
# 传统方式: {2: 4, 4: 16, 6: 36, 8: 64, 10: 100, 12: 144, 14: 196, 16: 256, 18: 324, 20: 400}
# 推导式方式: {2: 4, 4: 16, 6: 36, 8: 64, 10: 100, 12: 144, 14: 196, 16: 256, 18: 324, 20: 400}

# 3. 处理字典项的转换
# 传统方式
original_dict = {"a": 1, "b": 2, "c": 3}
uppercase_traditional = {}
for k, v in original_dict.items():
    uppercase_traditional[k.upper()] = v * 2

# 字典推导式
uppercase_comprehension = {k.upper(): v * 2 for k, v in original_dict.items()}

print(f"传统方式: {uppercase_traditional}")
print(f"推导式方式: {uppercase_comprehension}")
# 输出:
# 传统方式: {'A': 2, 'B': 4, 'C': 6}
# 推导式方式: {'A': 2, 'B': 4, 'C': 6}

字典推导式的局限性

何时不应使用字典推导式

# 1. 复杂逻辑不适合字典推导式
# 不推荐:过于复杂的字典推导式
complex_result = {
    f"key_{x}_{y}": x**2 + y**2 if (x + y) % 2 == 0 else (x - y)**2 
    for x in range(5) 
    for y in range(5) 
    if x != y and (x * y) % 3 == 0
}

# 推荐:使用传统for循环
complex_result = {}
for x in range(5):
    for y in range(5):
        if x != y and (x * y) % 3 == 0:
            if (x + y) % 2 == 0:
                complex_result[f"key_{x}_{y}"] = x**2 + y**2
            else:
                complex_result[f"key_{x}_{y}"] = (x - y)**2

# 2. 需要调试的情况
# 不推荐:难以调试
result = {k: complex_function(k) for k in range(100) if condition(k)}

# 推荐:便于调试
result = {}
for k in range(100):
    if condition(k):
        try:
            result[k] = complex_function(k)
        except Exception as e:
            print(f"Error processing {k}: {e}")

# 3. 需要打印中间结果
# 不推荐:无法打印中间结果
result = {k: process(k) for k in data}

# 推荐:可以打印调试信息
result = {}
for k in data:
    print(f"Processing {k}...")
    result[k] = process(k)

最佳实践

使用字典推导式的建议

# 1. 保持简洁
# 推荐:简单明了
squares = {x: x**2 for x in range(10)}

# 不推荐:过于复杂
result = {k: v if condition(k, v) else default(k, v) for k, v in data.items() if filter_condition(k, v)}

# 2. 使用有意义的变量名
# 推荐:清晰的变量名
word_lengths = {word: len(word) for word in words}

# 不推荐:模糊的变量名
d = {x: len(x) for x in y}

# 3. 合理使用条件
# 推荐:简单的条件筛选
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}

# 不推荐:复杂的嵌套条件
result = {k: v for k, v in data.items() if condition1(k) and condition2(v) or condition3(k, v)}

# 4. 考虑可读性
# 推荐:易于理解
name_to_age = {person["name"]: person["age"] for person in people}

# 不推荐:难以理解
result = {x["k"]: y["v"] for x, y in zip(a, b) if x["k"] in c}

总结

字典推导式是Python中创建和转换字典的强大工具,它具有以下特点:

  1. 简洁性:一行代码完成复杂的字典创建和转换
  2. 高效性:通常比传统for循环执行更快
  3. 可读性:意图明确,易于理解
  4. 灵活性:支持多种数据转换和过滤操作

在使用字典推导式时,应该:

  • 保持代码简洁明了
  • 使用有意义的变量名
  • 避免过于复杂的逻辑
  • 在需要调试时使用传统for循环

通过合理使用字典推导式,可以写出更加Pythonic和高效的代码。

« 上一篇 列表推导式 下一篇 » 集合推导式