趋近智
处理数据序列在数据科学中是基本的。很多时候,您需要根据现有列表创建新列表,或处理大型序列而无需占用过多内存。Python 为这些任务提供了优雅高效的工具:列表推导式和生成器表达式。它们为生成序列提供了比传统 for 循环更简洁的方法。
设想您有一个数字列表,并且想要创建一个包含每个数字平方的新列表。使用标准的 for 循环,您可能会这样写:
numbers = [1, 2, 3, 4, 5]
squares = []
for num in numbers:
squares.append(num * num)
print(squares)
# Output: [1, 4, 9, 16, 25]
这当然可以正常工作,但它需要初始化一个空列表,然后在循环中显式添加项。列表推导式让您可以用一行更易读的代码实现相同的结果。
基本语法是:[表达式 for 项 in 可迭代对象]
让我们使用列表推导式重写平方的例子:
numbers = [1, 2, 3, 4, 5]
squares = [num * num for num in numbers]
print(squares)
# Output: [1, 4, 9, 16, 25]
在这里,num * num 是应用于 可迭代对象 (numbers) 中每个 项 (此处命名为 num) 的表达式。结果是自动构建的新列表 squares。
列表推导式还可以包含 if 子句,用于从原始可迭代对象中筛选项目。
语法变为:[表达式 for 项 in 可迭代对象 if 条件]
假设您只想从列表中获取偶数的平方:
numbers = [1, 2, 3, 4, 5, 6]
even_squares = [num * num for num in numbers if num % 2 == 0]
print(even_squares)
# Output: [4, 16, 36]
if num % 2 == 0 条件确保只有当数字为偶数时,表达式 num * num 才会被求值并包含在结果列表中。
for 循环更易读。.append() 的显式 for 循环稍快,因为列表分配和元素插入在内部进行了优化。需要记住的是,列表推导式会立即在内存中创建整个新列表。对于中等大小的列表通常没问题,但对于非常大的数据集可能会出现问题。
如果您需要处理包含数百万甚至数十亿项的序列,或者一个理论上无限的序列怎么办?使用列表推导式将所有处理过的项加载到列表中会消耗大量内存,甚至可能无法实现。这就是生成器表达式的优势所在。
生成器表达式的语法与列表推导式非常相似,但使用圆括号 () 而非方括号 []:
(表达式 for 项 in 可迭代对象 if 条件)
关键在于,生成器表达式不会在内存中创建列表。相反,它会创建一个名为生成器的特殊对象。这个生成器充当迭代器,按需逐一生成项(通常被称为“惰性求值”)。
让我们修改平方的例子,使用生成器表达式:
numbers = [1, 2, 3, 4, 5]
squares_generator = (num * num for num in numbers)
print(squares_generator)
# Output: <generator object <genexpr> at 0x...> (地址会因系统而异)
请注意,直接打印生成器对象本身并不会显示平方后的数字。它只是告诉我们有一个生成器。要获取这些值,您需要对其进行迭代,例如,使用 for 循环或 next() 函数:
# 使用 for 循环迭代(最常见)
for square in squares_generator:
print(square, end=' ') # Output: 1 4 9 16 25
# 或者转换为列表(如果您最终需要完整列表)
# 注意:这会消耗生成器。您只能迭代一次。
# numbers = [1, 2, 3, 4, 5]
# squares_generator = (num * num for num in numbers)
# squares_list = list(squares_generator)
# print(squares_list) # Output: [1, 4, 9, 16, 25]
每次循环请求下一项时,生成器表达式只执行足以生成该下一项(1*1,然后 2*2,依此类推)并产出它。它不会计算或存储序列的其余部分,直到需要时才进行。
考虑处理一个大型日志文件中的行。您可能希望从每条符合特定模式的行中提取信息:
# 假设 'large_log_file.txt' 非常大
# 此代码逐行读取和处理,而无需加载整个文件
# with open('large_log_file.txt', 'r') as f:
# error_lines = (line.strip() for line in f if 'ERROR' in line)
# # 现在您可以迭代 error_lines
# for error in error_lines:
# # 逐一处理每一条错误行
# print(error)
使用生成器表达式 (line.strip() for line in f if 'ERROR' in line) 可以防止将整个潜在的超大文件加载到内存中。
选择主要取决于您对内存的要求以及打算如何使用生成的序列:
列表推导式和生成器表达式都是编写简洁、富有表现力且通常高效的 Python 代码的有力工具,在数据处理和机器学习流程中尤为宝贵,因为性能和内存管理是重要的考量。熟练掌握它们是编写更专业 Python 代码的一步。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造