推导式(Comprehension)是Python中一种简洁而强大的语法结构,用于快速创建序列(如列表、字典、集合)和生成器。推导式可以替代传统的循环和条件语句组合,使代码更加简洁、易读和高效。本文将详细介绍Python推导式的各种类型、用法和最佳实践。
一、推导式概述
1. 什么是推导式?
推导式是Python中用于快速创建新的数据结构的语法结构,它允许我们在一行代码中从一个或多个可迭代对象中创建新的数据结构。推导式的核心思想是将循环和条件判断组合在一个简洁的表达式中。
2. Python的推导式类型
Python主要提供四种类型的推导式:
- 列表推导式(List Comprehension)
- 字典推导式(Dictionary Comprehension)
- 集合推导式(Set Comprehension)
- 生成器表达式(Generator Expression)
3. 推导式的基本原理
推导式的基本原理是:
二、列表推导式
1. 基本语法
列表推导式用于创建列表,基本语法如下:
# 列表推导式的基本语法
[expression for item in iterable]
# 带有条件过滤的列表推导式
[expression for item in iterable if condition]
# 带有多个条件过滤的列表推导式
[expression for item in iterable if condition1 if condition2 ...]
# 带有else子句的列表推导式
[expression1 if condition else expression2 for item in iterable]
2. 基本用法
# 列表推导式的基本用法示例
# 创建1-10的平方列表
# 传统方法
squares =[]
for i inrange(1,11):
squares.append(i **2)
print(squares)# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 列表推导式
squares =[i **2for i inrange(1,11)]
print(squares)# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 创建1-10的偶数列表
# 传统方法
evens =[]
for i inrange(1,11):
if i %2==0:
evens.append(i)
print(evens)# [2, 4, 6, 8, 10]
# 列表推导式
evens =[i for i inrange(1,11)if i %2==0]
print(evens)# [2, 4, 6, 8, 10]
# 创建1-10的奇数列表
odds =[i for i inrange(1,11)if i %2!=0]
print(odds)# [1, 3, 5, 7, 9]
# 创建1-10的平方,只包含偶数的平方
even_squares =[i **2for i inrange(1,11)if i %2==0]
print(even_squares)# [4, 16, 36, 64, 100]
3. 带有else子句的列表推导式
# 带有else子句的列表推导式示例
# 将1-10的数字转换为"偶数"或"奇数"
number_types =["偶数"if i %2==0else"奇数"for i inrange(1,11)]
print(number_types)# ['奇数', '偶数', '奇数', '偶数', '奇数', '偶数', '奇数', '偶数', '奇数', '偶数']
# 对列表中的元素进行条件转换
numbers =[1,-2,3,-4,5,-6]
absolute_values =[i if i >0else-i for i in numbers]
print(absolute_values)# [1, 2, 3, 4, 5, 6]
# 根据成绩评级
scores =[95,82,76,64,55]
grades =["优秀"if score >=90else"良好"if score >=80else"中等"if score >=70else"及格"if score >=60else"不及格"for score in scores]
print(grades)# ['优秀', '良好', '中等', '及格', '不及格']
4. 嵌套列表推导式
嵌套列表推导式用于处理嵌套的可迭代对象:
# 嵌套列表推导式示例
# 扁平化二维列表
# 传统方法
matrix =[[1,2,3],[4,5,6],[7,8,9]]
flattened =[]
for row in matrix:
for num in row:
flattened.append(num)
print(flattened)# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 嵌套列表推导式
flattened =[num for row in matrix for num in row]
print(flattened)# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 生成二维列表(乘法表)
# 传统方法
table =[]
for i inrange(1,10):
row =[]
for j inrange(1, i +1):
row.append(f"{j}×{i}={i * j}")
table.append(row)
for row in table:
print("\t".join(row))
# 嵌套列表推导式
table =[[f"{j}×{i}={i * j}"for j inrange(1, i +1)]for i inrange(1,10)]
for row in table:
print("\t".join(row))
# 过滤嵌套列表中的元素
matrix =[[1,2,3],[4,5,6],[7,8,9]]
# 获取所有大于5的元素
greater_than_5 =[num for row in matrix for num in row if num >5]
print(greater_than_5)# [6, 7, 8, 9]
# 获取每行的偶数
row_evens =[[num for num in row if num %2==0]for row in matrix]
print(row_evens)# [[2], [4, 6], [8]]
5. 多个可迭代对象的列表推导式
可以在列表推导式中同时遍历多个可迭代对象:
# 多个可迭代对象的列表推导式示例
# 使用zip()函数同时遍历两个列表
# 传统方法
names =["张三","李四","王五"]
ages =[25,30,35]
people =[]
for name, age inzip(names, ages):
people.append(f"{name}今年{age}岁")
print(people)# ['张三今年25岁', '李四今年30岁', '王五今年35岁']
# 列表推导式
people =[f"{name}今年{age}岁"for name, age inzip(names, ages)]
print(people)# ['张三今年25岁', '李四今年30岁', '王五今年35岁']
# 遍历两个列表的笛卡尔积
# 传统方法
a =[1,2,3]
b =[4,5]
products =[]
for i in a:
for j in b:
products.append(i * j)
print(products)# [4, 5, 8, 10, 12, 15]
# 列表推导式
products =[i * j for i in a for j in b]
print(products)# [4, 5, 8, 10, 12, 15]
# 带有条件过滤的笛卡尔积
products =[i * j for i in a for j in b if i * j >5]
print(products)# [8, 10, 12, 15]
三、字典推导式
1. 基本语法
字典推导式用于创建字典,基本语法如下:
# 字典推导式的基本语法
{key_expression: value_expression for item in iterable}
# 带有条件过滤的字典推导式
{key_expression: value_expression for item in iterable if condition}
# 遍历两个可迭代对象的字典推导式
{key_expression: value_expression for key, value inzip(keys, values)}
2. 基本用法
# 字典推导式的基本用法示例
# 创建1-10的平方字典
# 传统方法
squares ={}
for i inrange(1,11):
squares[i]= i **2
print(squares)# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
# 字典推导式
squares ={i: i **2for i inrange(1,11)}
print(squares)# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
# 创建字符串长度字典
words =["apple","banana","orange","grape"]
# 传统方法
word_lengths ={}
for word in words:
word_lengths[word]=len(word)
print(word_lengths)# {'apple': 5, 'banana': 6, 'orange': 6, 'grape': 5}
# 字典推导式
word_lengths ={word:len(word)for word in words}
print(word_lengths)# {'apple': 5, 'banana': 6, 'orange': 6, 'grape': 5}
# 过滤字典中的元素
squares ={i: i **2for i inrange(1,11)}
# 只保留偶数的平方
even_squares ={k: v for k, v in squares.items()if k %2==0}
print(even_squares)# {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
3. 反转字典的键值对
# 反转字典的键值对示例
# 传统方法
original ={"a":1,"b":2,"c":3}
reversed_dict ={}
for k, v in original.items():
reversed_dict[v]= k
print(reversed_dict)# {1: 'a', 2: 'b', 3: 'c'}
# 字典推导式
reversed_dict ={v: k for k, v in original.items()}
print(reversed_dict)# {1: 'a', 2: 'b', 3: 'c'}
# 注意:如果原字典中有重复的值,反转后会丢失一些键值对
original ={"a":1,"b":2,"c":1}
reversed_dict ={v: k for k, v in original.items()}
print(reversed_dict)# {1: 'c', 2: 'b'}('a'键丢失)
4. 从两个列表创建字典
# 从两个列表创建字典示例
# 传统方法
keys =["name","age","city"]
values =["张三",30,"北京"]
person ={}
for k, v inzip(keys, values):
person[k]= v
print(person)# {'name': '张三', 'age': 30, 'city': '北京'}
# 字典推导式
person ={k: v for k, v inzip(keys, values)}
print(person)# {'name': '张三', 'age': 30, 'city': '北京'}
# 过滤不需要的键值对
keys =["name","age","city","phone"]
values =["张三",30,"北京",None]
person ={k: v for k, v inzip(keys, values)if v isnotNone}
print(person)# {'name': '张三', 'age': 30, 'city': '北京'}
5. 嵌套字典推导式
# 嵌套字典推导式示例
# 创建嵌套字典
# 传统方法
students ={}
for i inrange(1,4):
students[f"学生{i}"]={"id": i,"成绩":80+ i}
print(students)
# {'学生1': {'id': 1, '成绩': 81}, '学生2': {'id': 2, '成绩': 82}, '学生3': {'id': 3, '成绩': 83}}
# 字典推导式
students ={f"学生{i}":{"id": i,"成绩":80+ i}for i inrange(1,4)}
print(students)
# {'学生1': {'id': 1, '成绩': 81}, '学生2': {'id': 2, '成绩': 82}, '学生3': {'id': 3, '成绩': 83}}
# 过滤嵌套字典
students ={f"学生{i}":{"id": i,"成绩":80+ i}for i inrange(1,4)}
# 只保留成绩大于81的学生
top_students ={name: info for name, info in students.items()if info["成绩"]>81}
print(top_students)
# {'学生2': {'id': 2, '成绩': 82}, '学生3': {'id': 3, '成绩': 83}}
四、集合推导式
1. 基本语法
集合推导式用于创建集合,基本语法如下:
# 集合推导式的基本语法
{expression for item in iterable}
# 带有条件过滤的集合推导式
{expression for item in iterable if condition}
2. 基本用法
# 集合推导式的基本用法示例
# 创建1-10的平方集合
# 传统方法
squares =set()
for i inrange(1,11):
squares.add(i **2)
print(squares)# {1, 4, 9, 16, 25, 36, 49, 64, 81, 100}
# 集合推导式
squares ={i **2for i inrange(1,11)}
print(squares)# {1, 4, 9, 16, 25, 36, 49, 64, 81, 100}
# 从字符串创建字符集合(去重)
# 传统方法
word ="hello"
unique_chars =set()
for char in word:
unique_chars.add(char)
print(unique_chars)# {'h', 'e', 'l', 'o'}
# 集合推导式
unique_chars ={char for char in word}
print(unique_chars)# {'h', 'e', 'l', 'o'}
# 过滤集合中的元素
squares ={i **2for i inrange(1,11)}
# 只保留大于25的平方
greater_than_25 ={x for x in squares if x >25}
print(greater_than_25)# {36, 49, 64, 81, 100}
3. 集合推导式的去重功能
集合推导式的一个重要特性是自动去重:
# 集合推导式的去重功能示例
# 从列表创建去重集合
# 传统方法
numbers =[1,2,2,3,3,3,4,4,4,4]
unique_numbers =set()
for num in numbers:
unique_numbers.add(num)
print(unique_numbers)# {1, 2, 3, 4}
# 集合推导式
unique_numbers ={num for num in numbers}
print(unique_numbers)# {1, 2, 3, 4}
# 从字符串创建去重集合
word ="programming"
unique_chars ={char for char in word}
print(unique_chars)# {'p', 'r', 'o', 'g', 'a', 'm', 'i', 'n'}
# 带有条件过滤的去重
numbers =[1,2,2,3,3,3,4,4,4,4]
even_unique ={num for num in numbers if num %2==0}
print(even_unique)# {2, 4}
4. 嵌套集合推导式
# 嵌套集合推导式示例
# 扁平化嵌套列表并去重
# 传统方法
matrix =[[1,2,3],[3,4,5],[5,6,7]]
flattened =set()
for row in matrix:
for num in row:
flattened.add(num)
print(flattened)# {1, 2, 3, 4, 5, 6, 7}
# 集合推导式
flattened ={num for row in matrix for num in row}
print(flattened)# {1, 2, 3, 4, 5, 6, 7}
# 过滤嵌套列表中的元素
greater_than_3 ={num for row in matrix for num in row if num >3}
print(greater_than_3)# {4, 5, 6, 7}
五、生成器表达式
1. 基本语法
生成器表达式用于创建生成器,基本语法如下:
# 生成器表达式的基本语法
(expression for item in iterable)
# 带有条件过滤的生成器表达式
(expression for item in iterable if condition)
# 遍历两个可迭代对象的生成器表达式
(expression for item1 in iterable1 for item2 in iterable2)
2. 基本用法
# 生成器表达式的基本用法示例
# 创建1-10的平方生成器
# 传统方法(使用生成器函数)
defsquare_generator():
for i inrange(1,11):
yield i **2
squares = square_generator()
print(squares)# <generator object square_generator at 0x...>
for square in squares:
print(square, end=" ")
# 输出:1 4 9 16 25 36 49 64 81 100
# 生成器表达式
squares =(i **2for i inrange(1,11))
print(squares)# <generator object <genexpr> at 0x...>
for square in squares:
print(square, end=" ")
# 输出:1 4 9 16 25 36 49 64 81 100
# 带有条件过滤的生成器表达式
even_squares =(i **2for i inrange(1,11)if i %2==0)
for square in even_squares:
print(square, end=" ")
# 输出:4 16 36 64 100
3. 生成器表达式与列表推导式的区别
生成器表达式与列表推导式的主要区别在于:
- 列表推导式使用方括号
[],生成器表达式使用圆括号() - 列表推导式创建完整的列表,生成器表达式创建生成器对象
# 生成器表达式与列表推导式的区别示例
import sys
# 列表推导式(占用较多内存)
list_comp =[i for i inrange(1000000)]
print(f"列表推导式占用内存: {sys.getsizeof(list_comp)} 字节")
# 输出:列表推导式占用内存: 8697464 字节
# 生成器表达式(占用较少内存)
gen_expr =(i for i inrange(1000000))
print(f"生成器表达式占用内存: {sys.getsizeof(gen_expr)} 字节")
# 输出:生成器表达式占用内存: 104 字节
# 列表推导式可以多次访问
list_comp =[i for i inrange(5)]
print(list(list_comp))# [0, 1, 2, 3, 4]
print(list(list_comp))# [0, 1, 2, 3, 4]
# 生成器表达式只能遍历一次
gen_expr =(i for i inrange(5))
print(list(gen_expr))# [0, 1, 2, 3, 4]
print(list(gen_expr))# [](生成器已耗尽)
4. 生成器表达式的应用场景
生成器表达式适合处理大量数据或无限序列:
# 生成器表达式的应用场景示例
# 处理大文件
defprocess_large_file(file_path):
withopen(file_path,'r')asfile:
# 使用生成器表达式逐行处理文件
lines =(line.strip()for line infile)
for line in lines:
# 处理每一行
process_line(line)
# 生成无限序列
definfinite_sequence():
i =0
whileTrue:
yield i
i +=1
# 使用生成器表达式处理无限序列
even_numbers =(i for i in infinite_sequence()if i %2==0)
# 获取前10个偶数
count =0
for num in even_numbers:
print(num, end=" ")
count +=1
if count ==10:
break
# 输出:0 2 4 6 8 10 12 14 16 18
# 组合多个生成器
numbers1 =(i for i inrange(1,6))
numbers2 =(i for i inrange(6,11))
combined =(x + y for x in numbers1 for y in numbers2)
forsumin combined:
print(sum, end=" ")
# 输出:7 8 9 10 11 8 9 10 11 12 9 10 11 12 13 10 11 12 13 14 11 12 13 14 15
六、推导式的高级用法
1. 多层嵌套推导式
# 多层嵌套推导式示例
# 三层嵌套列表推导式
# 创建3x3x3的三维列表
matrix =[[[i + j + k for k inrange(3)]for j inrange(3)]for i inrange(3)]
print(matrix)
# [[[0, 1, 2], [1, 2, 3], [2, 3, 4]], [[1, 2, 3], [2, 3, 4], [3, 4, 5]], [[2, 3, 4], [3, 4, 5], [4, 5, 6]]]
# 三层嵌套字典推导式
# 创建嵌套字典
nested_dict ={f"外层{i}":{f"中层{j}":{f"内层{k}": i + j + k for k inrange(2)}for j inrange(2)}for i inrange(2)}
print(nested_dict)
# {'外层0': {'中层0': {'内层0': 0, '内层1': 1}, '中层1': {'内层0': 1, '内层1': 2}}, '外层1': {'中层0': {'内层0': 1, '内层1': 2}, '中层1': {'内层0': 2, '内层1': 3}}}
# 三层嵌套生成器表达式
gen =((i + j + k for k inrange(2))for j inrange(2)for i inrange(2))
for inner_gen in gen:
for num in inner_gen:
print(num, end=" ")
# 输出:0 1 1 2 1 2 2 3
2. 推导式中的函数调用
# 推导式中的函数调用示例
# 使用内置函数
words =["apple","banana","orange","grape"]
word_lengths ={word:len(word)for word in words}
print(word_lengths)# {'apple': 5, 'banana': 6, 'orange': 6, 'grape': 5}
# 使用自定义函数
defsquare(x):
return x **2
squares =[square(i)for i inrange(1,6)]
print(squares)# [1, 4, 9, 16, 25]
# 使用lambda函数
celsius =[0,10,20,30,40,50]
fahrenheit =[(lambda c: c *9/5+32)(c)for c in celsius]
print(fahrenheit)# [32.0, 50.0, 68.0, 86.0, 104.0, 122.0]
# 使用字符串方法
words =["Hello","WORLD","Python"]
lower_words =[word.lower()for word in words]
print(lower_words)# ['hello', 'world', 'python']
# 使用列表方法
matrix =[[1,2,3],[4,5,6],[7,8,9]]
flattened =[num for row in matrix for num in row]
print(flattened)# [1, 2, 3, 4, 5, 6, 7, 8, 9]
3. 推导式中的条件表达式
# 推导式中的条件表达式示例
# 复杂的条件表达式
numbers =[1,-2,3,-4,5,-6]
result =[i if i >0else-i if i <-3else0for i in numbers]
print(result)# [1, 0, 3, 4, 5, 6]
# 多个条件
scores =[95,82,76,64,55,40]
grades =["优秀"if s >=90else"良好"if s >=80else"中等"if s >=70else"及格"if s >=60else"不及格"for s in scores]
print(grades)# ['优秀', '良好', '中等', '及格', '不及格', '不及格']
# 嵌套条件
matrix =[[1,2,3],[4,5,6],[7,8,9]]
result =[num if num %2==0else-num for row in matrix for num in row if num >3]
print(result)# [-5, 6, -7, 8, -9]
七、推导式的性能分析
1. 时间性能
推导式通常比传统的循环和条件语句组合更快,因为它们是由C实现的,而不是Python字节码:
# 推导式的时间性能示例
import time
# 传统方法
deftraditional_method(n):
result =[]
for i inrange(n):
if i %2==0:
result.append(i **2)
return result
# 列表推导式
deflist_comprehension(n):
return[i **2for i inrange(n)if i %2==0]
# 测试性能
n =1000000
start_time = time.time()
traditional_method(n)
end_time = time.time()
print(f"传统方法耗时: {end_time - start_time:.6f}秒")
start_time = time.time()
list_comprehension(n)
end_time = time.time()
print(f"列表推导式耗时: {end_time - start_time:.6f}秒")
2. 内存性能
# 推导式的内存性能示例
import sys
# 列表推导式(占用较多内存)
list_comp =[i for i inrange(1000000)]
print(f"列表推导式占用内存: {sys.getsizeof(list_comp)} 字节")
# 生成器表达式(占用较少内存)
gen_expr =(i for i inrange(1000000))
print(f"生成器表达式占用内存: {sys.getsizeof(gen_expr)} 字节")
# 集合推导式
set_comp ={i for i inrange(1000000)}
print(f"集合推导式占用内存: {sys.getsizeof(set_comp)} 字节")
# 字典推导式
dict_comp ={i: i for i inrange(1000000)}
print(f"字典推导式占用内存: {sys.getsizeof(dict_comp)} 字节")
3. 性能优化建议
八、推导式的最佳实践
1. 代码可读性
# 代码可读性示例
# 不好的写法(过于复杂)
result =[x + y for x inrange(10)for y inrange(10)if x %2==0and y %2!=0]
# 好的写法(分解为多行)
result =[
x + y
for x inrange(10)# 遍历x
for y inrange(10)# 遍历y
if x %2==0# 只保留x为偶数
if y %2!=0# 只保留y为奇数
]
# 添加注释
even_squares =[
i **2# 计算平方
for i inrange(1,11)# 遍历1-10
if i %2==0# 只保留偶数
]
2. 避免常见的陷阱
# 避免常见的陷阱示例
# 错误:在推导式中修改外部变量
total =0
squares =[total := total + i **2for i inrange(1,6)]# Python 3.8+
print(total)# 55(外部变量被修改)
# 错误:重复使用生成器表达式
gen =(i for i inrange(5))
print(list(gen))# [0, 1, 2, 3, 4]
print(list(gen))# [](生成器已耗尽)
# 错误:字典推导式中的重复键
original ={"a":1,"b":2,"c":1}
reversed_dict ={v: k for k, v in original.items()}
print(reversed_dict)# {1: 'c', 2: 'b'}('a'键丢失)
# 错误:依赖集合推导式的顺序
colors ={"red","green","blue"}
color_list =[color for color in colors]
print(color_list)# 顺序可能不同,如 ['blue', 'green', 'red']
3. 选择合适的推导式类型
九、常见错误
1. 语法错误
# 语法错误示例
# 错误:缺少方括号
list_comp = i **2for i inrange(1,6)# 应该使用[]
# 错误:条件位置错误
list_comp =[i **2if i %2==0for i inrange(1,6)]# 条件应该在for之后
# 错误:多层嵌套的顺序错误
matrix =[[i + j for j inrange(3)]for i inrange(3)]# 正确
matrix =[[i + j for i inrange(3)]for j inrange(3)]# 顺序错误,结果不同
# 正确的写法
list_comp =[i **2for i inrange(1,6)]# 使用[]
list_comp =[i **2for i inrange(1,6)if i %2==0]# 条件在for之后
matrix =[[i + j for j inrange(3)]for i inrange(3)]# 正确的嵌套顺序
2. 逻辑错误
# 逻辑错误示例
# 错误:条件判断错误
even_squares =[i **2for i inrange(1,6)if i %2!=0]# 应该是i % 2 == 0
print(even_squares)# [1, 9, 25](错误,应该是[4, 16])
# 错误:变量作用域错误
i =10
squares =[i **2for i inrange(1,6)]
print(i)# 5(外部变量被修改)
# 错误:生成器表达式的误解
gen =(i for i inrange(5))
print(gen)# <generator object <genexpr> at 0x...>(不是列表)
# 正确的写法
even_squares =[i **2for i inrange(1,6)if i %2==0]
print(even_squares)# [4, 16]
# 避免变量作用域问题
original_i =10
squares =[i **2for i inrange(1,6)]
print(original_i)# 10(外部变量未被修改)
# 正确使用生成器表达式
gen =(i for i inrange(5))
print(list(gen))# [0, 1, 2, 3, 4]
3. 性能错误
# 性能错误示例
# 错误:对大型数据集使用列表推导式
data =[i for i inrange(100000000)]# 占用大量内存
# 错误:在推导式中使用耗时操作
defslow_function(x):
time.sleep(0.1)
return x **2
result =[slow_function(i)for i inrange(10)]# 耗时1秒
# 错误:过于复杂的嵌套推导式
result =[[[[i + j + k + l for l inrange(10)]for k inrange(10)]for j inrange(10)]for i inrange(10)]# 10^4 = 10000个元素
# 正确的写法
# 对大型数据集使用生成器表达式
data =(i for i inrange(100000000))
# 避免在推导式中使用耗时操作
# 考虑并行处理或异步处理
# 分解复杂的嵌套推导式
result =[]
for i inrange(10):
for j inrange(10):
for k inrange(10):
for l inrange(10):
result.append(i + j + k + l)
十、总结
Python推导式是一种强大而简洁的语法结构,可以显著提高代码的可读性和效率。本文介绍了四种主要的推导式类型:
- 列表推导式
- 字典推导式
- 集合推导式
- 生成器表达式
在使用推导式时,应注意:
通过掌握Python推导式的各种用法和最佳实践,可以编写出更简洁、更高效、更易读的Python代码。
发布网站:荣殿教程(zhangrongdian.com)
作者:张荣殿