python推导式

python推导式是一种简洁且强大的内建语法结构,它允许我们以一种极其紧凑和易于理解的方式创建新的列表字典集合生成器对象,能够更高效地操作和转换数据结构。

列表推导式基本语法如下图:

其他推导式的语法也基本相似,看着有点lambda的感觉,上面图片遍历一个名为oldlist的列表,并将大于0的元素逐一进行双倍运算后,添加至新列表newlist中。接下来我们逐一分析各个推导式:

目录

一、列表推导式

二、推导式中使用函数解决复杂情况

1、表达式较复杂

2、推导条件较复杂

三、推导式中的嵌套表达式(了解写法即可)

四、字典推导式

五、集合推导式

六、元组推导式(生成器表达式)


一、列表推导式

通过一行代码即可从一个已存在的可迭代对象(如列表、元组或其他序列)中生成一个新的列表,接着用前面的例子来讲:

#方法一
oldlist=[-1,0,-3,1,2,3]
newlist=[]
for i in oldlist:
    if i > 0:
        newlist.append(i*2)
print(newlist)


#方法二
newlist = [i * 2 for i in oldlist if i > 0]
print(newlist)

#同样处理列表,使用了python推导式后,代码省了不少,简洁明了。

再来看一个使用列表推导式对数据进行过滤和转换的实例:

#设我们有一个包含用户信息的列表,每个元素是一个字典,表示每位用户的属性(如姓名、年龄和邮箱地址)。
# 现在我们需要创建一个新的列表,只包含年龄大于20岁的用户,并将他们的邮箱地址全部转换为小写。
users = [
    {'name': 'Alice', 'age': 20, 'email': 'Alice@gmail.com'},
    {'name': 'yang', 'age': 18, 'email': 'Yang@gmail.com'},
    {'name': 'Bob', 'age': 21, 'email': 'BOB@gmail.com'},
    {'name': 'Eve', 'age': 24, 'email': 'EvE@gmail.com'}
]
new_users = [{'name':user['name'],'age':user['age'],'email':user['email'].lower()}
             for user in users if user['age']>20]
print(new_users)

在上述代码中,列表推导式 [{"name": user["name"], "email": user["email"].lower()} for user in users if user["age"] > 20] 的作用是:

1、遍历 users 中的每个 user 字典。

2、使用条件 if user["age"] > 20 筛选出年龄大于20岁的用户。

3、对于满足条件的用户,创建一个新的字典,其中 "name" 键的值保持不变,而 "email" 键的值通过调用 .lower() 方法转换为小写。

运行这段代码后,new_users 将会是一个新的列表,包含如下内容:

[{'name': 'Bob', 'age': 21, 'email': 'bob@gmail.com'},

{'name': 'Eve', 'age': 24, 'email': 'eve@gmail.com'}]

上面的例子条件语句都是在推导式结尾,我们再来看看一种条件语句在表达式中的例子:

#我们有个列表,里面有字符串,也有数字,现在将数字转换为字符串,将字符串转换为大写
oldlist = [1, 'a', 2, 'b', 3, 'c']
newlist = [str(i) if isinstance(i, int) else i.upper() for i in oldlist]
print(newlist)

通过上述例子,我们可以总结一下:

1、推导式从一个可枚举数据(列表,元组,集合,字典等)推导出一个列表。

2、推导式可以加推导条件,只对符合条件的元素推导

3、要推导出的元素使用表达式生成,可以用if else生成不同元素(处理生成推导结果的过程较复杂的情况)

二、推导式中使用函数解决复杂情况

如果表达式或者推导条件特别复杂怎么办?可以使用函数,例子如下:

1、表达式较复杂

#例1、假设我们有一个用户列表,除了年龄和邮箱地址之外,还包括用户的注册日期(格式为字符串),
#现在我们需要筛选出年龄大于20岁的用户,并将他们的邮箱地址转换为小写,同时计算他们注册至今的天数。

# 原始用户信息列表,添加了注册日期字段
users = [
    {'name': 'Alice', 'age': 20, 'email': 'Alice@gmail.com',"reg_date": "2018-01-01"},
    {'name': 'yang', 'age': 18, 'email': 'Yang@gmail.com',"reg_date": "2017-01-01"},
    {'name': 'Bob', 'age': 21, 'email': 'BOB@gmail.com',"reg_date": "2015-01-01"},
    {'name': 'Eve', 'age': 24, 'email': 'EvE@gmail.com',"reg_date": "2023-01-01"}
]
# 自定义函数,用于计算从注册日期到现在的天数
def days_since_reg(date_string):
    reg_date = datetime.strptime(date_string, "%Y-%m-%d")
    today = datetime.now()
    return (today - reg_date).days

# 利用列表推导式结合自定义函数进行筛选、转换和计算
filtered_users = [{"name": user["name"],"email": user["email"].lower(),"days_since_reg": days_since_reg(user["reg_date"])}
                  for user in users if user["age"] > 20]
print(filtered_users)

''' 输出
[{'name': 'Bob', 'email': 'bob@gmail.com', 'days_since_reg': 3357}, {'name': 'Eve', 'email': 'eve@gmail.com', 'days_since_reg': 435}]



'''
# 例2、推导1949年到2024年的所有年份,标记出闰年和平年
def run_year(year):
    if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
        return True
    else:
        return False

yearlist = [f'润年{year}' if run_year(year) else f'平年{year}' for year in range(1949, 2025)]
print(yearlist)
''' 输出
['平年1949', '平年1950', '平年1951', '润年1952', '平年1953', '平年1954', '平年1955', '润年1956', 
'平年1957', '平年1958', '平年1959', '润年1960', '平年1961', '平年1962', '平年1963', '润年1964', 
'平年1965', '平年1966', '平年1967', '润年1968', '平年1969', '平年1970', '平年1971', '润年1972', 
'平年1973', '平年1974', '平年1975', '润年1976', '平年1977', '平年1978', '平年1979', '润年1980', 
'平年1981', '平年1982', '平年1983', '润年1984', '平年1985', '平年1986', '平年1987', '润年1988',
'平年1989', '平年1990', '平年1991', '润年1992', '平年1993', '平年1994', '平年1995', '润年1996',
'平年1997', '平年1998', '平年1999', '润年2000', '平年2001', '平年2002', '平年2003', '润年2004', 
'平年2005', '平年2006', '平年2007', '润年2008', '平年2009', '平年2010', '平年2011', '润年2012', 
'平年2013', '平年2014', '平年2015', '润年2016', '平年2017', '平年2018', '平年2019', '润年2020',
'平年2021', '平年2022', '平年2023', '润年2024']
'''

2、推导条件较复杂

直接上例子:

#推导1~10中的所有质数

# 定义函数判断一个数是否是质数
def is_prime(num):
    if num == 1:
        return False
    for i in range(2, num):
        if (num % i) == 0:
            return False
    else:
        return True

p_nums = [i for i in range(1, 10) if is_prime(i)] #推导条件使用定义函数
print(p_nums)  #输出[2, 3, 5, 7]

三、推导式中的嵌套表达式(了解写法即可)

用例子演示:

# 假设有一个二维坐标点的列表,如果x和y不相等,则将(x, y)作为一个点添加到新列表中
list1=[(x,y) for x in range(1,3) for y in range(1,4) if x!=y]
print(list1) #输出[(1, 2), (1, 3), (2, 1), (2, 3)]
#相当于:
list_n=[]
for x in range(1,3):
    for y in range(1,4):
        if x!=y:
            list_n.append((x,y))
print(list_n)

有两层循环的相对来说下面的写法会更易懂一点,不建议写嵌套,我们知道写法即可

四、字典推导式

推导字典的方式和推导列表很相似,区别在:1、使用大括号 2、使用键值对。看例子:

# 1、将键值对列表转换为字典
key_value = [('name', 'Harry'), ('age', 18)]
# 使用字典推导式创建字典
dc = {k: v for k, v in key_value}
print(dc)  # 输出:{'name': 'Harry', 'age': 18}

# 2、基于另一个字典生成新字典,同时修改值:
original_dict = {'麦叔': 59, '张三': 87, 'FGA': 78, '石石': 100, '莫名': 90}
# 创建一个新字典,其中每个值增加10岁
new_dict = {k: v + 10 for k, v in original_dict.items()}
print(new_dict)

# 3、过滤字典,只保留满足条件的键值对:
scores = {'麦叔': 59, '张三': 87, 'FGA': 78, '石石': 100, '莫名': 90}
# 只保留分数在90分以上的同学信息
high_scores = {k: v for k, v in scores.items() if v >= 90}
print(high_scores)

# 4、将两个相同键的字典合并,合并时按值相加:
dict1 = {'a': 1, 'b': 2}
dict2 = {'a': 3, 'b': 4, 'c': 5}
# 合并两个字典,相同键的值相加
merged_dict = {k: dict1.get(k, 0) + dict2.get(k, 0) for k in set(dict1.keys()).union(dict2.keys())}
print(merged_dict)

五、集合推导式

推导集合的方式和列表是一样的,区别在于:1、使用大括号,类似于推导字典,但它是单个元素,而不是键值对  2、集合会自动过滤掉重复的元素。

#1、生成包含偶数的集合:
numbers = [1, 2, 3, 4, 5, 6]
even_numbers=[x for x in numbers if x%2==0]
print(even_numbers) # 输出:[2, 4, 6]

#2、基于列表中的元素计算平方得到新的集合:
list_num=[1, 2, 3, 4, 5, 6]
squares = {x**2 for x in list_num}
print(squares) #{1, 4, 36, 9, 16, 25}

六、元组推导式(生成器表达式)

元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 ( ) 圆括号将各部分括起来,而列表推导式用的是中括号 [ ],另外元组推导式返回的结果是一个生成器对象。

#1:创建一个包含数字平方的元组
tuple1=(i**2 for i in range(1,5))
print(tuple1) # <generator object <genexpr> at 0x0000020101BA5E00>
print(next(tuple1)) # 输出:1
print(tuple(tuple1)) # 输出:(4, 9, 16)

#2:从另一个序列中筛选元素并转换为元组
words = ['apple', 'banana', 'cherry', 'date', 'elderberry']
long_words = tuple(word for word in words if len(word) > 5)
print(long_words)  # 输出: ('banana', 'cherry', 'elderberry')

#3:将两个列表一一对应组合成元组,并合并为一个元组序列
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
paired_tuples = tuple((x, y) for x, y in zip(list1, list2))
print(paired_tuples)  # 输出: ((1, 'a'), (2, 'b'), (3, 'c'))

'''
注意,在实际应用中,由于元组是不可变的数据结构,
因此通常我们会利用其不可变性来存储一次性生成的结果或者作为临时的数据结构。
在上述例子中,如果需要多次迭代结果,可能更适合用列表推导式,
但若只遍历一次或空间效率要求较高时,元组推导式更为适合。
'''

在Python中,如果列表推导式需要处理大量数据并且生成的中间结果占用巨大内存时,可以考虑使用生成器表达式来替代。生成器表达式不会一次性将所有结果存储到内存中,而是按需产生结果,这对于处理大数据流非常有效。

# 假设有一个巨大的数字序列,我们想计算每个数的平方但内存有限
# huge_numbers = [x**2 for x in range(10**10)]
# 这段代码很可能会卡死电脑,不建议运行,除非你的电脑是超级计算机。因为它要在内存中做100亿次计算,然后保存这100亿个数字。

# 生成器表达式方式:
huge_squares = (x**2 for x in range(10**10))
print(huge_squares) #输出 <generator object <genexpr> at 0x0000020101BA5E00>
print(next(huge_squares)) #输出 0
print(next(huge_squares)) #输出 1
print(next(huge_squares)) #输出 4
print(next(huge_squares)) #输出 9

#这是一个生成器,它不会一次性生成100亿个数字,只有调用next()的时候,
#它才会生成一个新的,返回给你。也就是说,同一个时间,只保存一个数字。
#每次调用 next() 都会计算并返回生成器的下一个元素,直到生成器中的元素被全部遍历完。

在这个例子中,如果我们用列表推导式一次性计算range(10**10)中所有整数的平方并存储起来,将会消耗大量内存。而使用生成器表达式,则可以逐个生成并处理这些平方值,从而有效地控制内存使用量。生成器在python中是一种非常实用和高效的工具,它的功能有点像一个“懒惰的计算器”,只计算你当下需要的结果,而不是一次性算出所有结果并存储起来。下次单独更新关于生成器迭代器等处理序列数据的工具。

综上所述,总结如下

推导式的优点:

1、代码简洁,易于阅读和理解,能够以一行表达式的形式实现复杂的数据转换逻辑。

2、内存高效,尤其是生成器表达式(元组/字典推导式在创建时占用空间,但生成器仅在迭代时产生值)。

推导式的缺点:

1、如果需要多次迭代或修改结果,由于列表推导式生成的是不可变序列(元组推导式)或一次性创建所有元素(列表推导式),它们不如普通循环加append灵活。

2、对于非常大的数据集,可能会造成内存压力,尤其是在不恰当使用列表推导式一次性生成全部结果时。

常用场景:

1、数据清洗和转换:如筛选、映射、组合等操作,例如从一个列表中筛选出满足特定条件的元素并转换为新的格式。

2、创建新序列:基于现有序列快速生成一个新的有序集合,如计算数字序列的平方、立方或者将两个序列配对生成元组。

3、函数参数传递:用于生成函数所需的参数序列,比如用在 zip()map() 或其他高阶函数中。

希望以上内容能帮助到大家合理运用python的推导式~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/447992.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最迟但到的 Star History 2023 年度开源精选!

千呼万唤始出来&#xff0c;Star History 2023 年终开源精选来啦&#xff01;&#x1f389; AI 是 2023 开源领域里最主要的关键词&#xff0c;但其实过去一年还是有很多其他值得关注的项目和发展趋势的&#xff01;Star History 小编总结了几个类别并精选了类别中最亮眼的项目…

ElasticSearchLinux安装和springboot整合的记录和遇到的问题

前面整合遇到的一些问题有的记录在下面了&#xff0c;有的当时忘了记录下来&#xff0c;希望下面的能帮到你们 1&#xff1a;Linux安装ES 下载安装&#xff1a; 参考文章&#xff1a;连接1 连接2 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch…

校园小情书微信小程序源码 | 社区小程序前后端开源 | 校园表白墙交友小程序

项目描述&#xff1a; 校园小情书微信小程序源码 | 社区小程序前后端开源 | 校园表白墙交友小程序 功能介绍&#xff1a; 表白墙 卖舍友 步数旅行 步数排行榜 情侣脸 漫画脸 个人主页 私信 站内消息 今日话题 评论点赞收藏 服务器环境要求&#xff1a;PHP7.0 MySQL5.7 效果…

【三十】springboot项目上高并发解决示例

互相交流入口地址 整体目录&#xff1a; 【一】springboot整合swagger 【二】springboot整合自定义swagger 【三】springboot整合token 【四】springboot整合mybatis-plus 【五】springboot整合mybatis-plus 【六】springboot整合redis 【七】springboot整合AOP实现日志操作 【…

c++ primer plus 笔记 第十六章 string类和标准模板库

string类 string自动调整大小的功能&#xff1a; string字符串是怎么占用内存空间的&#xff1f; 前景&#xff1a; 如果只给string字符串分配string字符串大小的空间&#xff0c;当一个string字符串附加到另一个string字符串上&#xff0c;这个string字符串是以占用…

并发容器介绍(二)

并发容器介绍&#xff08;二&#xff09; 文章目录 并发容器介绍&#xff08;二&#xff09;BlockingQueueBlockingQueue 简介ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue ConcurrentSkipListMap 文章来自Java Guide 用于学习如有侵权&#xff0c;立即删除 Bl…

大模型字典中加入特殊字符

大模型字典中加入特殊字符 在微调大模型的时候会遇到添加特殊字符&#xff0c;例如在微调多轮的数据的时候需要加入人和机器等特殊标识字符&#xff0c;如用这个特殊字符表示人&#xff0c;用这个特殊字符表示机器&#xff0c;从而实现了人机对话。一般在大模型中base字典中不…

二次供水无人值守解决方案

二次供水无人值守解决方案 二次供水系统存在一定的管理难题和技术瓶颈&#xff0c;如设备老化、维护不及时导致的水质安全隐患&#xff0c;以及如何实现高效运行和智能化管理等问题。在一些地区&#xff0c;特别是老旧小区或农村地区&#xff0c;二次供水设施建设和改造滞后&a…

【go语言开发】redis简单使用

本文主要介绍redis安装和使用。首先安装redis依赖库&#xff0c;这里是v8版本&#xff1b;然后连接redis&#xff0c;完成基本配置&#xff1b;最后测试封装的工具类 文章目录 安装redis依赖库连接redis和配置工具类封装代码测试 欢迎大家访问个人博客网址&#xff1a;https://…

初学Vue——Vue路由

0 什么是Vue路由 类似于Html中的超链接(<a>)一样&#xff0c;可以跳转页面的一种方式。 前端路由&#xff1a;URL中hash(#号之后的内容)与组件之间的对应关系&#xff0c;如下图&#xff1a; 当我们点击左侧导航栏时&#xff0c;浏览器的地址栏会发生变化&#xff0c;路…

hutool,真香!

大家好&#xff0c;我是苏三&#xff0c;又跟大家见面了。 前言 今天给大家介绍一个能够帮助大家提升开发效率的开源工具包&#xff1a;hutool。 Hutool是一个小而全的Java工具类库&#xff0c;通过静态方法封装&#xff0c;降低相关API的学习成本&#xff0c;提高工作效率&…

IOT的发展历程及其优势——青创智通

工业互联网-物联网-设备改造-IOT-青创智通 ​随着科技的不断发展&#xff0c;物联网&#xff08;IoT&#xff09;已经逐渐成为了我们生活中不可或缺的一部分。IoT是指通过互联网将各种物理设备连接起来&#xff0c;实现设备之间的数据交换和智能化控制。IoT的发展不仅改变了我们…

四管齐下 共建发展 | 七巧低代码助力零售行业打造一体化协同解决方案

行业背景 随着互联网和移动技术的普及&#xff0c;零售行业的销售渠道日趋多元化和融合化&#xff0c;传统线下渠道和新兴线上渠道相互竞争和协作&#xff0c;形成了新零售和全渠道的格局。快消品新零售模式下&#xff0c;企业需要通过数字化和智能化的手段&#xff0c;实现对…

Flask python 开发篇:项目布局

一、背景简介 Flask应用程序可以像单个文件一样简单。就像上一篇简单实现一个接口一样&#xff0c;所有的东西都在一个python文件内&#xff1b; 然而&#xff0c;当项目越来越大的时候&#xff0c;把所有代码放在单个文件中就有点不堪重负了。 Python 项目使用 包 来管理代码…

携手亚信安慧AntDB,在数智化浪潮中乘风破浪

随着大数据时代的到来&#xff0c;对数据库的需求愈发强烈。在这一背景下&#xff0c;国产数据库逐渐崭露头角&#xff0c;亚信安慧AntDB作为重要的代表产品之一正积极参与到激烈的市场竞争中。亚信安慧AntDB不仅追求技术的革新和突破&#xff0c;同时也致力于满足用户日益增长…

【Python】conda 命令报错解决:Example: conda --no-plugins install <package>

目录 报错效果&#xff1a;解决方法总结 欢迎关注 『Python』 系列&#xff0c;持续更新中 欢迎关注 『Python』 系列&#xff0c;持续更新中 报错效果&#xff1a; An unexpected error has occurred. Conda has prepared the above report. If you suspect this error is bei…

OD_2024_C卷_200分_9、园区参观路径【JAVA】【动态规划】

package odjava;import java.util.Scanner;public class 九_园区参观路径 {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt(); // 长 -> 行数int m sc.nextInt(); // 宽 -> 列数int[][] matrix new int[n][m]; // 地图…

HAproxy反向代理与负载均衡

目录 一、HAproxy介绍 1. 概述 2. 关于4/7层负载均衡 2.1 无负载均衡 2.1.1 图示 2.1.2 说明 2.2 四层负载均衡 2.2.1 图示 2.2.2 说明 2.3 七层负载 2.3.1 图示 2.3.2 说明 3. 特性 4. HAProxy负载均衡常见策略 5. 处理模式 二、HAproxy安装 1. yum安装 2. 第…

算法---双指针练习-7(三数之和)

三数之和 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;三数之和 2. 讲解算法原理 首先对输入的数组进行排序&#xff0c;以便后续使用双指针法。初始化一个空的二维向量 ret&#xff0c;用于存储结果。使用一个循环遍历数组中的每个元素&#xff…

Spark性能优化指南——高级篇

调优概述 有的时候&#xff0c;我们可能会遇到大数据计算中一个最棘手的问题——数据倾斜&#xff0c;此时Spark作业的性能会比期望差很多。数据倾斜调优&#xff0c;就是使用各种技术方案解决不同类型的数据倾斜问题&#xff0c;以保证Spark作业的性能。 数据倾斜发生时的现…