0

0

Python中列表推导式详细教程 Python中列表推导式用法实例

冰火之心

冰火之心

发布时间:2025-08-26 16:58:01

|

1035人浏览过

|

来源于php中文网

原创

列表推导式是一种简洁高效的创建列表的方式,核心语法为[表达式 for 变量 in 可迭代对象 if 条件],支持单层或多层嵌套、多条件过滤,相比传统循环更高效且更具可读性,但在复杂逻辑或大数据场景下应避免过度使用,可结合生成器表达式优化内存消耗。

python中列表推导式详细教程 python中列表推导式用法实例

Python中的列表推导式,说白了,就是一种非常Pythonic、简洁高效的创建列表的方式。它能让你用一行代码,优雅地完成原本需要好几行循环和

append
操作才能做到的事情。对我个人而言,它不仅仅是语法糖,更是一种思维模式的转变,一旦掌握,写起代码来会感觉流畅很多。

解决方案

列表推导式的核心语法结构是这样的:

[表达式 for 变量 in 可迭代对象 if 条件]

我们来拆解一下:

  • 表达式
    : 这是对
    变量
    进行操作后,最终要放入新列表的元素。它可以是
    变量
    本身,也可以是
    变量
    的某个属性,或者
    变量
    经过函数处理后的结果。
  • for 变量 in 可迭代对象
    : 这部分和我们平时写的
    for
    循环非常相似,它会遍历
    可迭代对象
    中的每一个元素,并将其赋值给
    变量
  • if 条件
    (可选)
    : 这是一个筛选器。只有当
    条件
    True
    时,
    表达式
    才会被计算并加入到新的列表中。如果没有
    if
    条件,那么
    可迭代对象
    中的所有元素(经过
    表达式
    处理后)都会被包含进去。

举个最简单的例子,如果我想创建一个包含1到5的平方的列表:

立即学习Python免费学习笔记(深入)”;

# 传统方法
squares = []
for i in range(1, 6):
    squares.append(i * i)
print(squares) # 输出: [1, 4, 9, 16, 25]

# 列表推导式
squares_lc = [i * i for i in range(1, 6)]
print(squares_lc) # 输出: [1, 4, 9, 16, 25]

你看,一行代码就搞定了。再来一个带条件筛选的:找出1到10之间的所有偶数。

# 传统方法
evens = []
for num in range(1, 11):
    if num % 2 == 0:
        evens.append(num)
print(evens) # 输出: [2, 4, 6, 8, 10]

# 列表推导式
evens_lc = [num for num in range(1, 11) if num % 2 == 0]
print(evens_lc) # 输出: [2, 4, 6, 8, 10]

这种写法,不仅代码量减少了,在我看来,它也更直接地表达了“我想要一个列表,里面是满足某个条件的元素经过某种处理后的结果”这个意图。

Python列表推导式与传统循环:效率与可读性对比如何?

谈到列表推导式,很多人首先想到的就是它比传统

for
循环更快、更简洁。这确实是事实,但背后的原因和实际应用中的权衡,我觉得还是值得深入聊聊的。

效率上看,列表推导式通常会比等价的

for
循环加
append
操作要快。这主要是因为Python在底层对列表推导式进行了优化。当我们使用
for
循环时,每次
append
操作都可能涉及到函数调用和动态内存分配。而列表推导式在内部实现时,C语言级别的优化允许它更有效地预分配内存,减少了Python解释器执行的字节码指令数量。我个人在处理大量数据时,如果性能是关键考量,列表推导式往往是我的首选。你可以用
timeit
模块简单测试一下,结果通常会让你惊喜。

import timeit

# 传统循环
time_for_loop = timeit.timeit('[i*i for i in range(1000000)]', number=100)
print(f"传统循环耗时: {time_for_loop:.4f} 秒")

# 列表推导式
time_list_comp = timeit.timeit('list(map(lambda i: i*i, range(1000000)))', number=100) # 故意写错,这里应该是列表推导式本身
# Corrected for comparison:
time_list_comp = timeit.timeit('[i*i for i in range(1000000)]', number=100)
print(f"列表推导式耗时: {time_list_comp:.4f} 秒")

(自我修正:上面的

list(map(lambda i: i*i, range(1000000)))
虽然也是一种方式,但与列表推导式的直接比较,应该用列表推导式本身的代码。我有时候也会犯这种小迷糊,但重要的是能及时发现并纠正。)

可读性角度来看,这就有点见仁见智了。对于简单的转换和过滤任务,列表推导式无疑是更简洁、更“Pythonic”的表达方式。它将整个列表创建的逻辑紧凑地封装在一行中,一眼就能看出其目的。然而,如果你的逻辑变得非常复杂,比如涉及到多层嵌套循环、多个复杂的条件判断,或者需要在循环内部执行一些有副作用的操作(比如修改外部变量),那么列表推导式可能会变得难以理解,甚至成为“一行地狱”。在这种情况下,我个人会毫不犹豫地选择传统的

for
循环,因为它能提供更清晰的步骤分解和更易于调试的结构。代码首先是给人读的,其次才是给机器执行的,可读性在很多时候比极致的简洁更重要。

掌握Python列表推导式的高级用法:嵌套与多条件过滤

列表推导式不仅仅能处理简单的单层循环和单条件筛选,它在处理更复杂的数据结构时也能大显身手,比如嵌套多条件过滤

嵌套列表推导式 当你需要处理一个包含列表的列表(比如矩阵),或者想将一个嵌套的结构扁平化时,嵌套列表推导式就非常方便。它的写法和我们传统的嵌套

for
循环非常相似,只是顺序有点不同。

假设我们有一个数字矩阵:

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

如果我们想把这个矩阵扁平化成一个一维列表:

flattened_list = [num for row in matrix for num in row]
print(flattened_list) # 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]

这里的

for row in matrix for num in row
,你可以想象成外层循环
for row in matrix
,内层循环
for num in row
。在写的时候,内层循环写在前面,这和传统
for
循环的嵌套顺序刚好相反,初学者可能会有点不适应,但习惯了就好。

阿里云AI平台
阿里云AI平台

阿里云AI平台

下载

再比如,我们想创建一个新的矩阵,其中每个元素是原矩阵对应元素的平方:

squared_matrix = [[num * num for num in row] for row in matrix]
print(squared_matrix)
# 输出: [[1, 4, 9], [16, 25, 36], [49, 64, 81]]

这里外层的

[... for row in matrix]
负责遍历每一行,内层的
[num * num for num in row]
则负责处理行内的每个元素。不过,我得提醒一句,嵌套层级太深的话,列表推导式的可读性会急剧下降。我个人通常建议最多两层嵌套,再复杂就考虑用传统循环或者封装成函数了。

多条件过滤

if
条件部分,我们可以使用逻辑运算符
and
or
来组合多个条件。这让我们的筛选逻辑更加灵活。

例如,从1到20中找出所有既是偶数又是5的倍数的数字:

filtered_numbers = [num for num in range(1, 21) if num % 2 == 0 and num % 5 == 0]
print(filtered_numbers) # 输出: [10, 20]

如果条件变得非常复杂,比如需要检查多个属性,或者涉及一些复杂的计算,我可能会选择将条件封装到一个辅助函数中,让列表推导式保持简洁,只负责调用这个函数。

def is_special_number(n):
    return n > 10 and n % 3 == 0 and n % 2 != 0 # 找出大于10的奇数且是3的倍数

special_numbers = [num for num in range(1, 30) if is_special_number(num)]
print(special_numbers) # 输出: [15, 21, 27]

这样做的好处是,

is_special_number
函数的逻辑可以单独测试和维护,而列表推导式本身依然清晰明了。

Python列表推导式常见误区与最佳实践:避免性能陷阱

列表推导式虽好用,但用不好也可能带来一些问题。作为一名开发者,我觉得识别这些误区并遵循最佳实践,能帮助我们写出更健壮、更高效的代码。

常见误区:

  1. 过度复杂化: 这是我经常看到的一个问题。有人试图把所有的逻辑,包括复杂的条件判断、多层嵌套,甚至一些有副作用的操作,都塞进一个列表推导式里。结果就是一行代码长得像“天书”,难以理解和维护。我个人认为,如果一个列表推导式需要你花超过几秒钟来理解它的意图,那它可能就已经过度复杂了。
  2. 追求副作用: 列表推导式的主要目的是创建新的列表。如果你在
    表达式
    中调用了一个函数,而这个函数的主要目的是修改外部变量或者执行I/O操作(比如打印),那这通常是一个代码异味。列表推导式应该尽可能地保持纯粹,即只根据输入产生输出,不产生其他副作用。
  3. 内存消耗: 列表推导式会一次性生成所有元素并存储在一个列表中。如果你的可迭代对象非常大,比如一个包含百万甚至千万元素的生成器,那么生成的列表可能会占用大量的内存,导致程序变慢甚至崩溃(
    MemoryError
    )。这其实是一个很实际的问题,尤其是在处理大数据时。

最佳实践:

  1. 保持简洁和专注: 列表推导式最适合简单的转换和过滤。如果你的逻辑开始变得复杂,考虑将其分解成多个步骤,或者使用传统的

    for
    循环。代码的可读性往往比所谓的“一行代码”更重要。

  2. 明确意图: 当你使用列表推导式时,确保你的意图是清晰地从一个可迭代对象中创建或转换出一个新的列表。避免将其用于其他目的。

  3. 善用生成器表达式(Generator Expressions): 当你处理非常大的数据集,或者你不需要一次性将所有结果都存储在内存中,而只需要逐个处理时,生成器表达式是列表推导式的绝佳替代品。它的语法和列表推导式非常相似,只是用圆括号

    ()
    代替了方括号
    []

    # 列表推导式 (生成整个列表)
    large_list = [i*i for i in range(10**7)] # 可能会占用大量内存
    
    # 生成器表达式 (惰性求值,按需生成)
    large_generator = (i*i for i in range(10**7)) # 不会立即计算所有值
    # 只有当你迭代它的时候,元素才会被生成
    for item in large_generator:
        # 处理 item
        if item > 100:
            break

    生成器表达式不会一次性构建整个列表,而是返回一个迭代器,每次请求时才计算下一个值。这在处理大数据流或者只需要部分结果时,能显著节省内存。对我来说,这是一个非常重要的性能优化手段。

  4. 测试和调试: 尽管列表推导式很简洁,但在出现问题时,调试可能会有点挑战。如果你的列表推导式出现错误,可以尝试将其拆分成传统的

    for
    循环来定位问题。熟练掌握调试技巧总是有益的。

总的来说,列表推导式是Python提供的一个强大工具,它能让你的代码更简洁、更高效。但像所有工具一样,关键在于理解它的适用场景和潜在的限制,并根据具体情况做出明智的选择。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

410

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

638

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

362

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

263

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

631

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

564

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

671

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

618

2023.09.22

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号