超详细,Python列表解析式到底该怎么用?
Python 是一种极其多样化和强大的编程语言!当需要解决一个问题时,它有着不同的方法。
在本文中,将会展示列表解析式(List Comprehension)。我们将讨论如何使用它?什么时候该或不该使用它?喜欢本文记得收藏、关注、点赞。
注:完整代码、数据、技术交流文末获取
列表解析式的优势
比循环更节省时间和空间。
需要更少的代码行。
可将迭代语句转换为公式。
如何在 Python 中创建列表
列表解析式是一种基于现有列表创建列表的语法结构。让我们来看看创建列表的不同实现
循环
循环是创建列表的传统方式。不管你使用什么样的循环。要以这种方式创建列表,您应该:
实例化一个空列表。
循环遍历一个可迭代的(如
range
)的元素。将每个元素附加到列表的末尾。
numbers = []
for number in range(10):numbers.append(number)print(numbers)
输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
在此示例中,您实例化了一个空列表 numbers
。然后使用 for
循环迭代 range(10)
并使用 append()
方法将每个数字附加到列表的末尾。
map() 对象
map()
是创建列表的另一种方法。您需要向 map()
传递一个函数和一个可迭代对象,之后它会创建一个对象。该对象包含使用指定函数执行每个迭代元素所获得的输出。
例如,我们将呈现在某些产品的价格中增加增值税的任务。
VAT_PERCENT = 0.1 # 10%def add_vat(price):return price + (price * VAT_PERCENT)prices = [10.03, 8.6, 32.85, 41.5, 22.64]
grand_prices = map(add_vat, prices)
print(grand_prices)
grand_prices = list(grand_prices)
print(grand_prices)
您已经构建了 add_vat()
函数并创建了 prices
可迭代对象。您将这两个参数都传递给 map()
并收集生成的 map
对象 grand_prices
,或者您可以使用 list()
轻松地将其转换为列表。
输出:
<map object at 0x7f18721e7400> # map(add_vat, prices)
[11.03, 9.46, 36.14, 45.65, 24.9] # list(grand_prices)
列表解析式
现在,让我们看一下列表解析式方法!这确实是 Python 风格,并且是创建列表的更好方法。为了弄清楚这种方法有多强大,我们用一个单行代码来重写那个循环示例。
numbers = [number for number in range(10)]
print(numbers)
输出
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
正如您所见,这是一种不可思议的方法!列表解析式看起来足够可读,您不需要编写更多代码,而只需一行。
为了更好地理解列表,请查看以下语法格式:
new_list = [expression for member in iterable]
哪种方法更有效
好的,我们已经学习了如何使用循环、map()
和列表解析式来创建列表,在您的脑海中可能会提出“哪种方法更有效”的问题。我们来分析一下吧!
import random
import timeitVAT_PERCENT = 0.1
PRICES = [random.randrange(100) for x in range(100000)]def add_vat(price):return price + (price * VAT_PERCENT)def get_grand_prices_with_map():return list(map(add_vat, PRICES))def get_grand_prices_with_comprehension():return [add_vat(price) for price in PRICES]def get_grand_prices_with_loop():grand_prices = []for price in PRICES:grand_prices.append(add_vat(price))return grand_pricesprint(timeit.timeit(get_grand_prices_with_map, number=100))
print(timeit.timeit(add_grand_prices_with_comprehension, number=100))
print(timeit.timeit(get_grand_prices_with_loop, number=100))
输出:
0.9833468980004909 # with_map
1.197223742999995 # with_comprehension
1.3564663889992516 # with_loop
正如我们现在所看到的,创建列表的最优的方法是 map()
,排在第二位的是列表解析式,最后是循环。
但是,方法的选择应取决于您想要实现的目标。
使用
map()
可以使你的代码更高效。使用循环可以使代码的思路展现更加清晰。
使用列表解析式可以您使代码更加紧凑,且较高效。这是创建列表的最佳方式,因为这种方式可读性最强。
高级解析式
条件逻辑
早些时候,我向您展示了这个公式:
new_list = [expression for member in iterable]
公式可能有些不完整。对解析式的更加完整描述增加了对可选条件的支持。将条件逻辑添加到列表解析式的最常见方法是在表达式的末尾添加条件:
new_list = [expression for member in iterable (if conditional)]
在这里,您的条件语句正好位于右边的括号中。
条件很重要,因为它们允许列表解析式过滤掉不需要的值,这在一般情况下也可以调用 filter()
:
numbers = [number for number in range(20) if number % 2 == 0]
print(numbers)
输出:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
正如您所看到的那样,这个解析式收集了可被 2 整除且没有余数的数字。
如果您需要更复杂的过滤器,那么您甚至可以将条件逻辑移动到单独的函数中。
def is_prime(number):if number > 1:for el in range(2, int(number/2)+1):if (number % el) == 0:return False else:return Truenumbers = [number for number in range(20) if is_prime(number)]
print(numbers)
输出:
[2, 3, 5, 7, 11, 13, 17, 19]
您构建 is_prime(number)
以确定是否是素数并返回布尔值。接下来,您应该将函数添加到解析式的条件中。
该公式允许您使用条件逻辑从几个可能的输出选项中进行选择。例如,您有一个产品价格表,若有负数,您应将其转换为正数:
price_list = [1.34, 19.01, -4.2, 6, 8.78, -1,1]
normalized_price_list = [price if price > 0 else price*-1 for price in price_list]
print(normalized_price_list)
输出:
[1.34, 19.01, 4.2, 6, 8.78, 1,1]
在这里,您的表达式 price
有一个条件语句,如果 price > 0 else price*-1
。这会告诉 Python,如果价格为正,则输出价格值;但如果价格为负,则将价格转换为正值。该功能很强大,考虑将条件逻辑视为其自身的函数的确是很有用的:
def normalize_price(price):return price if price > 0 else price*-1price_list = [1.34, 19.01, -4.2, 6, 8.78, -1,1]
normalized_price_list = [normalize_price(price) for price in price_list]
print(normalized_price_list)
输出:
[1.34, 19.01, 4.2, 6, 8.78, 1,1]
集合解析式
您还可以创建一个集合解析式!它基本与列表解析式相同。不同之处在于集合解析式不包含重复项。您可以通过使用花括号取代方括号来创建集合解析式:
string = "Excellent"
unique_string = {letter for letter in string}
print(unique_string)
输出:
{"E", "e", "n", "t", "x", "c", "l"}
你的集合解析式只包含唯一的字母。这与列表不同,集合不保证项目将以特定顺序存储数据。这就是为什么集合输出的第二个字母是 e
,即使字符串中的第二个字母是 x
。
字典解析式
字典解析式也是是类似的,但需要定义一个键:
string = "Words are but wind"
word_order = {el: ind+1 for ind, el in enumerate(string.split())}
print(word_order)
输出:
{"Words": 1, "are": 2, "but": 3, "wind": 4}
要创建 word_order
字典,请在表达式中使用花括号 ({}
) 以及键值对 (el: ind+1
)。
海象运算符
Python 3.8 中引入的海象运算符允许您一次解决两个问题:为变量赋值,返回该值。
假设您需要对将返回温度数据的 API 应用十次。您想要的只是 100 华氏度以上的结果。而每个请求可能都会返回不同的数据。在这种情况下,没有办法在 Python 中使用列表解析式来解决问题。可迭代成员(如果有条件)的公式表达式无法让条件将数据分配给表达式可以访问的变量。
海象运算符解决了这个问题。它允许您在执行表达式的同时将输出值分配给变量。以下示例显示了这是如何实现的,使用 get_weather_data()
生成伪天气数据:
import randomdef get_weather_data():return random.randrange(90, 110)hot_temps = [temp for item in range(20) if (temp := get_weather_data()) >= 100]
print(hot_temps)
输出:
[108, 100, 106, 103, 108, 106, 103, 104, 109, 106]
什么时候不要使用解析式
列表解析式非常有用,它可以帮助您编写清晰且易于阅读和调试的代码。但在某些情况下,它们可能会使您的代码运行速度变慢或使用更多内存。如果它让您的代码效率更低或更难理解,那么可以考虑选择另一种方式。
注意嵌套的解析式
可以通过嵌套解析式以创建列表、字典和集合的组合集合(译者注:这个集合不是指 set 对象类型,而是 collection,泛指容器)。例如,假设一家公司正在跟踪一年中五个不同城市的收入。存储这些数据的完美数据结构可以是嵌套在字典解析式中的列表解析式。
cities = ['New York', 'Oklahoma', 'Toronto', 'Los Angeles', 'Miami']
budgets = {city: [0 for x in range(12)] for city in cities}
print(budgets)
输出:
{"NewYork": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],"Oklahoma": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],"Toronto": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],"LosAngeles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],"Miami": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
您使用字典解析式创建了 budgets
容器。该表达式是一个键值对,其中包含另一个解析式。此代码将快速生成城市中每个 city
的数据列表。
嵌套列表是创建矩阵的常用方法,通常用于数学目的。查看下面的代码块:
matrix = [[x for x in range(7)] for y in range(6)]
print(matrix)
输出:
[[0, 1, 2, 3, 4, 5, 6],[0, 1, 2, 3, 4, 5, 6],[0, 1, 2, 3, 4, 5, 6],[0, 1, 2, 3, 4, 5, 6],[0, 1, 2, 3, 4, 5, 6],[0, 1, 2, 3, 4, 5, 6]
]
外部列表解析式 [... for y in range(6)]
创建了六行,而内部列表解析式 [x for x in range(7)]
将用值填充这些行中的每一行。
到目前为止,每个嵌套解析式的目标都是真正且直观的。但是,还有一些其他情况,例如创建扁平化的嵌套列表,其中的逻辑可以使您的代码非常难以阅读。让我们看下面的例子,使用嵌套列表解析式来展平一个矩阵:
matrix = [[0, 1, 0],[1, 0, 1],[2, 1, 2],
]
flat = [num for row in matrix for num in row]
print(flat)
输出:
[0, 1, 0, 1, 0, 1, 2, 1, 2]
扁平化矩阵的代码确实很简洁,但是太难理解了,您应该花点时间弄清楚它是如何工作的。另一方面,如果您使用 for
循环来展平相同的矩阵,那么您的代码将更加简单易读:
matrix = [[0, 1, 0],[1, 0, 1],[2, 1, 2],
]
flat = []
for row in matrix:for num in row:flat.append(num)
print(flat)
输出:
[0, 1, 0, 1, 0, 1, 2, 1, 2]
现在,您可以看到代码一次遍历矩阵的一行,在移动到下一行之前取出该行中的所有元素。
虽然嵌套列表解析式可能看起来更具有 Python 风格,但对于能够编写出您的团队可以轻松理解和修改的代码来才是更加最重要的。当选择一个方法时,您应该根据解析式是有助于还是有损于可读性来做出相应的判断。
为大型数据集使用生成器
Python 中的列表解析式通过将整个列表存储到内存中来工作。对于小型至中型列表这通常很好。如果您想将前一千个整数相加,那么列表解析式将轻松地解决此任务:
summary = sum([x for x in range(1000)])
print(summary)
输出:499500
但是,如果您需要对十亿个数字求和呢?您可以尝试执行此操作,但您的计算机可能不会有响应。这是可能因为计算机中分配大量内存。也许您是因为计算机没有如此多的内存资源。
例如,你想要一些第一个十亿整数,那么让我们使用生成器!这可能多需要一些时间,但计算机应该可以克服它:
summary = sum((x for x in range(1000000000)))
print(summary)
输出:
499999999500000000
让我们来对比一下哪种方法是更优的!
import timeitdef get_sum_with_map():return sum(map(lambda x: x, range(1000000000)))def get_sum_with_generator():return sum((x for x in range(1000000000)))print(timeit.timeit(get_sum_with_map, number=100))
print(timeit.timeit(get_sum_with_generator, number=100))
输出:
4940.844053814 # get_sum_with_map
3464.1995523349997 # get_sum_with_generator
正如您所见,生成器比 map()
高效得多。
总结
本文向您介绍了列表解析式,以及如何使用它来解决复杂的任务,而不会使您的代码变得过于困难。
现在你:
学习了几种创建列表的替代方法。
找出每种方法的优点。
可以简化循环和 map() 调用列表解析式。
理解了一种将条件逻辑添加到解析式中的方法。
可以创建集合和字典解析式。
学会了何时不使用解析式。
感谢您阅读本文直到结束!
推荐文章
李宏毅《机器学习》国语课程(2022)来了
有人把吴恩达老师的机器学习和深度学习做成了中文版
上瘾了,最近又给公司撸了一个可视化大屏(附源码)
如此优雅,4款 Python 自动数据分析神器真香啊
梳理半月有余,精心准备了17张知识思维导图,这次要讲清统计学
年终汇总:20份可视化大屏模板,直接套用真香(文末附源码)
技术交流
欢迎转载、收藏、有所收获点赞支持一下!
目前开通了技术交流群,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友
- 方式①、发送如下图片至微信,长按识别,后台回复:加群;
- 方式②、添加微信号:dkl88191,备注:来自CSDN
- 方式③、微信搜索公众号:Python学习与数据挖掘,后台回复:加群
超详细,Python列表解析式到底该怎么用?相关推荐
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(四)
手把手讲解超详细python入门游戏项目'打外星飞船'(四) 在经过创立屏幕.飞船移动和设置子弹,我们这里开始设置外形人的创建和移动.我们这里主要的任务是:创建一众外星人让它们充满屏幕,让他们向下和两 ...
- python详细安装教程-超详细Python与PyCharm安装教程,看这一篇就够了
原标题:超详细Python与PyCharm安装教程,看这一篇就够了 学习了三天的python, 之前测试一直用课程自带的网页版玩玩, 为了学习 然后就下载了一个python和pycharm 现在分享下 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(二)
手把手讲解超详细python入门游戏项目'打外星飞船'(二) 上次我们在(一)中创建了游戏的背景,现在我们这里将要实现用键盘控制飞船的移动.射击子弹,但是在此之前我们还有一个非常重要的部分–重构. 重 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(五)
手把手讲解超详细python入门游戏项目'打外星飞船'(五) 这是最后一个项目了,前面我们讲了整个游戏页面的控制.飞船.子弹.外星人的创建,这里我们讨论一下子弹射杀外星人和整个游戏的结束,我们这里的文 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(三)
手把手讲解超详细python入门游戏项目'打外星飞船'(三) 第三部分我们讲解一下飞船需要射出子弹,那么子弹的部分是怎么操作呢?接下来我直接把项目的四个文件展示出来,以注释的形式在旁边讲解.因为有很多 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(一)
手讲解超详细python入门游戏项目'打外星飞船'手把(一) 由于内容比较多,这里会分为五篇文章来讲解,从页面的创建.飞船控制.射击.外星人创建.射杀外星人五片来展开. 做一个窗口和设置响应用户 im ...
- 神器 VS Code,超详细Python配置使用指南
作者:Lemon 出品:Python数据之道 神器 VS Code, 超详细Python配置使用指南 大家好,我是 Lemon. 之前在公众号发了关于 PyCharm 与 VS Code 对比的文章, ...
- # 手把手教学超详细python通用爬虫分布式框架(一)
手把手教学超详细python通用爬虫分布式框架(一) ` 这里日后添加系列文章的所有文章的目录 文章目录 手把手教学超详细python通用爬虫分布式框架(一) 前言 一.所谓任务? 二.任务需要什么 ...
- 【超详细Python教学课件分享】寻宝探路
您好,感谢您一直对少儿编程.对"与非学堂"的关注.为了更好地为大家服务,诚邀您填写一份<关于少儿编程教与学的课件资源素材需求调查>,https://www.wjx.cn ...
最新文章
- 如何实现文字翻译,这个技巧你需要掌握
- yii2之原生sql
- java文件与流_Java文件和流深入
- .Net 事件类型的实现和推荐做法
- 并发编程实践三:Condition
- 用了十年的昵称badboy_怎样用5秒钟看清一对夫妻的真实感情状况?
- 【课题总结】OpenCV 抠图项目实战(12)源程序代码
- Android 系统(240)---底层如何简易的获取一个从AP传下来的parameter(flag)
- 脚本之家python专题_一个简单的python读写文件脚本
- 《DOOM启世录(纪念版) 》此书出了纪念版,好像内容没变
- php安装失败,PHP编译安装时常见错误解决办法
- python getattrribute_补8.python之面相对象part.7(类相关函数的补充)
- 在java里四舍五入怎么做_利用java怎么实现一个四舍五入功能
- ASUS华硕天选2 FX506H INTELI711代CPU 原装出厂系统恢复原厂系统
- CocosCreator H5 微信内置浏览器调起微信支付
- javaweb常识类英语
- 4.4 赋值运算符,4.5 递增和递减运算符
- SpringBoot#InitBinder
- DDS的DXT5格式解析
- 【Python】200行的文字RPG游戏