Python | 优雅的列表推导式
提出问题
- 生成 1-20 的列表
a
。 - 挑出列表
a
中偶数,存为列表b
。 - 将列表
b
的所有元素平方,生成列表c
。
分析问题
采用 for
循环,加条件判断,很轻松就可以实现。但有没有更简洁的实现方式?列表推导式(List Comprehension)。对比看看两者的效果。
实现过程
for 循环
# 生成列表
a = []
for i in range(20):
a.append(i)
# 条件判断
b = []
for i in a:
if i % 2 == 0:
b.append(i)
# 计算
c = []
for i in b:
c.append(i**2)
# 结果展示
print(a)
print(b)
print(c)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
列表推导式
a = [i for i in range(20)]
b = [x for x in a if x % 2 == 0]
c = [x**2 for x in b]
# 结果展示
print(a)
print(b)
print(c)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
二者比较
语法
对比两段实现代码,语法差异一目了然。用 for
和 if
语法如下:
for (set of values to iterate):
if (conditional filtering):
output_expression()
写作列表推导式如下:
[ output_expression() for(set of values to iterate) if(conditional filtering) ]
速度
Do you know List Comprehensions are 35% faster than FOR loop and 45% faster than map function? (AARSHAY JAIN, JANUARY 19, 2016)
import timeit
# for 循环
def gen_lst(n):
lst = []
for i in range(n):
lst.append(i)
return lst
for_loop = timeit.timeit(stmt="gen_lst(1000)",
setup="from __main__ import gen_lst", number=100000)
# stmt 需要测试的函数或语句,字符串形式
# setup 运行的环境,本例子中表示 if __name__ == '__main__':
# number 被测试的函数或语句,执行的次数,本例表示执行100000次 gen_lst()。默认是10000次
# 所以,此函数表示在if __name__ == '__main__'的条件下,执行100000次gen_lst()消耗的时间
# 列表推导式
lst_comp = timeit.timeit(stmt="[x for x in range(1000)]",
setup="from __main__ import gen_lst", number=100000) # 4.470719099999769
print("for循环耗时:{}n列表推导式耗时:{}".format(
for_loop, lst_comp))
# for 循环耗时:8.945164900000002
# 列表推导式耗时:4.339412200000002
为什么列表推导式比 for
循环更快呢?这是由字节码决定的。在 for
循环中先要加载 append
方法,然后再执行后续运算;而列表推导式则直接调用了 LIST_APPEND
命令来添加元素。就是这个区别使列表推导式比循环更快,当嵌套多层循环和判断的情况下对比更明显。
实现 for 和 map() 函数
# 需求:将列表所有元素除以 10
lst = [100,1000,10000,100000]
# for 循环
new_lst = map(lambda x:x/10,lst)
# 列表推导式
new_lst = [x/10 for x in lst]
列表推导式的应用
拉平矩阵
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
# for 循环
flattened = []
for row in matrix:
for i in row:
flattened.append(i)
# 列表推导式
flattened = [i for row in matrix for i in row] # [1, 2, 3, 4, 5, 6, 7, 8, 9]
矩阵转置
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
# for 循环
transposed = []
for i in range(3):
trans_row = []
for row in matrix:
trans_row.append(row[i])
transposed.append(trans_row)
# 列表推导式
transposed = [[row[i] for row in matrix] for i in range(3)]
# NumPy
import numpy as np
arr = np.array(matrix)
arr.T
小结
本文由最简单的列表生成和计算入手,比较了 for
循环和列表推导式的语法和速度等方面的特点,并展示了列表推导式的运用。其实列表推导式还有更多的应用,有兴趣可以阅读这份 Tutorial[1] 。
总体来看,列表推导式比 for 循环更简洁和优雅,而且速度更快。但列表推导式写起来爽,读起来并不爽,代码的可读性没有用循环清晰。所以在使用列表推导式的时,需要注意代码的可读性。
在《流畅的 Python》中,作者建议通常的原则是,只用列表推导式来创建新的列表,并且尽量保持简短。如果列表推导式的代码超过了两行,看是否考虑用循环重写。用循环还是列表推导式和创作文章一样,没有硬性的规定,但要自己把握好度。
参考资料
[1]
Tutorial – Python List Comprehension With Examples: https://www.analyticsvidhya.com/blog/2016/01/python-tutorial-list-comprehension-examples/
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 微信开发系列之四 - 将SAP C4C的数据更改通知发送到微信公众号上
- 微信开发系列之三 - 在微信公众号里发起SAP C4C Account的创建
- 微信开发系列之二 - 在微信公众号里开发一个自动应答的图灵机器人
- 微信开发系列之一 - 微信公众号开发的开发环境搭建
- SAP Commerce开发之如何找到某个页面对应的JSP实现页面
- 如何用代码读取SAP CRM的Categorization Schema
- 如何使用代码创建SAP CRM Service Request subject
- 微信开发系列之八 - 微信公众号的地图集成
- vivo 悟空活动中台 - 栅格布局方案
- 使用literal或者绑定变量执行SAP HANA SQL语句
- dotnet OpenXML 如何判断是形状还是文本
- dotnet 执行 docker 容器 error MSB4018 CreateAppHost 任务意外失败可能原因
- dotnet 定制 ILogger 实现
- dotnet 在 UOS 国产系统上安装 Mono 开发工具的方法
- dotnet 在 Linux 下的 GDI 库对 EMF 图片格式的支持