【笔记】效率之门——Python中的函数式编程技巧

文章目录
- Python函数式编程
- 1. 数据
- 2. 推导式
- 3. 函数式编程
- 3.1. Lambda函数
- 3.2. python内置函数
- 3.3. 高阶函数
- 4. 函数式编程的应用
Python函数式编程
我的AI Studio项目:【笔记】LearnDL第三课:Python高级编程——抽象与封装 - 飞桨AI Studio (baidu.com)
python中函数式编程的一些技巧,可以提升我们编写代码的效率,写出更加清晰且高效的代码。
开发者关心两个效率,
- 程序运行的效率:程序用更少的计算资源完成更多的任务。
- 编写代码的效率:程序员在更少的时间实现更多的功能。
随着计算机算力的不断增长,如今我们更加关心的往往是后者。
本文主要包含以下内容:
- 函数应当如何使用数据
- 使用列表推导式或字典推导式简化代码
- 使用Lambda函数,简化代码
- python中一些内置函数的使用技巧
- 什么是高阶函数
- 使用函数式编程的技巧完成一个小任务
最后一节“函数式编程的应用”中用到了一个图像数据集,在AI Studio中可以使用它。
1. 数据
- 数据的状态——尤为重要
- 不修改外部环境,不影响输入,多次调用函数不会产生不同的结果
- 避免可变的状态
- 尽量使用不可变的数据结构。例如list可变,而tuple不可变。
# 返回斐波那契数列的某一项
def fib(i):if i > 1:return fib(i - 1) + fib(i - 2)else:return 1
print(fib(5))
8
使用可变的数据结构,例如list,有时会踩坑,例如作为函数的默认参数时,下面是一个例子。
你惊讶地发现,put(10)和put(5)竟然输出了一样的结果,而你单独运行put(5)时又能得到正确的结果。
def put(n, x=[1, 1]):while len(x) < n:x.append(x[-1] + x[-2])return xprint(put(10))
print(put(5))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
原因就是,两次调用put函数时,默认参数[1, 1]都是同一个对象,例如可以打印出对象的id(相当于在内存中的地址)看一下,发现两次调用put函数都在直接操作同一个list对象。
def put(n, x=[1, 1]):print(id(x))while len(x) < n:x.append(x[-1] + x[-2])return x
put(10), put(5)
140357520173648
140357520173648
([1, 1, 2, 3, 5, 8, 13, 21, 34, 55], [1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
而使用不可变的数据对象作为函数的默认参数,就不会出现该问题。之前因为默认参数list本身也是一个对象实例,“可变”就是可以被篡改;而元组对象本身是无法修改的,后面代码怎么写都不会影响默认参数的值。
下面的例子中,你发现两次调用时元组x的id还是相同的,但是转换成的list的id就不同了,put(5)也得到了正确的结果。
def put(n, x=(1, 1)):print("tuple:", id(x))x = list(x)print("list: ", id(x))while len(x) < n:x.append(x[-1] + x[-2])return x
put(10), put(5)
tuple: 140357563320112
list: 140357519739872
tuple: 140357563320112
list: 140357519346416
([1, 1, 2, 3, 5, 8, 13, 21, 34, 55], [1, 1, 2, 3, 5])
2. 推导式
列表推导式与字典推导式,可以提升我们编码的效率,以及程序运行的效率。
例如前面的put函数,使用推导式,函数体仅需一行代码,而且代码逻辑也清晰易懂。
# 列表推导式
def put(n):return [fib(i) for i in range(n)]
print(put(5))# 字典推导式
def put(n):return {i:fib(i) for i in range(n)}
print(put(5))
[1, 1, 2, 3, 5]
{0: 1, 1: 1, 2: 2, 3: 3, 4: 5}
3. 函数式编程
善用一些函数式编程技巧,提高编程效率。
- Lambda函数
- python内置函数
- sum:求和
- all:有一个None就返回False
- any:有一个不是None,就返回True
- reduce:自定义求和方式
- 高阶函数
3.1. Lambda函数
Lambda定义的函数,与def定义的函数是等价的,但是在形式上更简单。
f = lambda a, b : a + b
print(f(1, 2))def f(a, b):return a + b
print(f(1, 2))
3
3
Lambda与其它迭代器对象结合使用,有时会十分方便。例如,生成一个完全平方数列:
# 生成一个完全平方数列
x = list(map(lambda x : x * x, range(11)))
print(x)
# 找到数列中以‘1’结尾的数字,组成一个新的数列
x = list(filter(lambda x : str(x).endswith("1"), x))
print(x)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[1, 81]
3.2. python内置函数
关于python内置函数,下面给出几个示例代码。其中all和any常用于有效数据的筛选。
x = [1, 2, 3, 4, 5]
print(sum(x))
x = [1, 2, 3, None, 5]
print(all(x))
x = [None, None, 3, None, None]
print(any(x))
x = ['a', 'b', 'c', 'd']
reduce(lambda x, y : x * 2 + y, x)
15
False
True
'aabaabcaabaabcd'
reduce可能看起来不太好懂,其实这里的“求和”对于字符串而言就是“连接”,x作为之前的和传入,y就是下一项,(其实和sum的求和还是很相似的,可以仔细比较一下)。过程如下:
- a * 2 + b = aab
- aab * 2 + c = aabaabc
- aabaabc * 2 + d = aabaabcaabaabcd
3.3. 高阶函数
在python中,函数其实可以玩得挺花。例如,函数可以作为返回值,也可以作为函数的参数。
# 1. 函数作为返回值
# 这里例子中,函数k()的定义受函数f()的控制
def f(n):def k(x):return n * xreturn kF = f(3)
print(F(2)) # 2. 函数作为参数
def F(x, f):x = f(x)return x * x
print(F(1, lambda x : x + 1))
6
4
4. 函数式编程的应用
对于一个任务,先梳理需求,把共性、重复的地方抽象出来,再统一安排。
例如下面的任务:
- 将两个image文件夹归类至dataset/image文件夹,并将文件按照顺序重新编号
待处理数据集结构:
- PlantSegmentationDatasets- vinecuttings- images- masks- weeds- weed50images- weed50masks
images文件夹中都是".JPG"后缀的文件,weed50images中既有".JPG"也有".png"。
首先,我们要得到待复制的所有文件,
dir_1 = "/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/"
dir_2 = "/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/"# 1. glob模糊匹配
paths = glob(dir_1 + "*.JPG")
for path in paths[:5]:print(path)# 2. 列表推导式 --> 匹配多种文件后缀
# 此时得到了一个两层嵌套的列表 [[], [], [], []]
ends = ["*.JPG", "*.jpg", "*.png", "*.jpeg"]
paths = [glob(dir_2 + end) for end in ends]
print(paths)# 3. reduce(求和) --> 拼接嵌套列表为一层
paths = reduce(lambda x, y : x + y, paths)
for path in paths[:5]:print(path)
输出:
输出内容过长, 已自动对输出内容进行截断
/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/DSC00149.JPG
/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/DSC00241.JPG
/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/DSC00248.JPG
/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/DSC00214.JPG
/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/DSC00200.JPG[['/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_SpurredAnoda_0026.JPG', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_SpurredAnoda_035.JPG'], [], ['/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0035-YuzhenLu(C).png', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0021-YuzhenLu(B).png', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0031-YuzhenLu.png', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0035-YuzhenLu(A).png', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0017-YuzhenLu(B).png', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0042-YuzhenLu.png', '/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_Nikon/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_SpurredAnoda_0026.JPG
/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_SpurredAnoda_035.JPG
/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0035-YuzhenLu(C).png
/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0021-YuzhenLu(B).png
/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/08192020_NikonD3300_YL_Carpetweed_0031-YuzhenLu.png
下面是完整的代码:
# 将in_dirs里每个目录的图片,分别复制到同一个out_dir中,并为它们重新编号
def copy_dir(in_dirs, out_dir):!mkdir $out_dir # 创建文件夹for j, in_dir in enumerate(in_dirs):ends = ["*.JPG", "*.png", "*.jpg", "*.jpeg"]paths = reduce(lambda x, y : x + y, [glob(in_dir + end) for end in ends])for i, in_filename in enumerate(paths):out_filename = out_dir + str(j) + "_" + str(i) + ".jpg"print(out_filename)!cp $in_filename $out_filename # 复制图片dir_1 = "/home/aistudio/PlantSegmentationDatasets/vinecuttings/images/"
dir_2 = "/home/aistudio/PlantSegmentationDatasets/weeds/weed50images/"
out_dir = "/home/aistudio/data/image/"
in_dirs = [dir_1, dir_2]
copy_dir(in_dirs, out_dir)
更多的应用,就以后在实践中慢慢摸索咯。
完
相关文章:
【笔记】效率之门——Python中的函数式编程技巧
文章目录Python函数式编程1. 数据2. 推导式3. 函数式编程3.1. Lambda函数3.2. python内置函数3.3. 高阶函数4. 函数式编程的应用Python函数式编程 我的AI Studio项目:【笔记】LearnDL第三课:Python高级编程——抽象与封装 - 飞桨AI Studio (baidu.com) p…...
Java【多线程基础2】 Thread类 及其常用方法
文章目录前言一、Thread类1, 构造方法2, 常用成员属性3, 常用成员方法3.1, start 启动线程3.2, interrupt 中断线程 (重点)3.2.1, 手动设置标记位3.2.2, 使用内置标记位3.3.3, interrupt 方法 的作用3.3 sleep 休眠线程3.4, jion 等待线程3.5 获取当前线程的引用总结前言 各位读…...
JVM调优实战及常量池详解
目录 阿里巴巴Arthas详解 Arthas使用场景 Arthas使用 GC日志详解 如何分析GC日志 CMS G1...
ChatGPT研究分析:GPT-4做了什么
前脚刚研究了一轮GPT3.5,OpenAI很快就升级了GPT-4,整体表现有进一步提升。追赶一下潮流,研究研究GPT-4干了啥。本文内容全部源于对OpenAI公开的技术报告的解读,通篇以PR效果为主,实际内容不多。主要强调的工作…...
我为什么要写博客,写博客的意义是什么??
曾经何时我也不知道,怎样才能变成我自己所羡慕的大佬!!在一次次的CSDN阅读的过程中,结实了许多志同道合的人!!包过凉哥,擦姐……大佬,但是,很遗憾,与这些人只…...
ssm框架之spring:浅聊AOP
AOP(Aspect Oriented Programming),是一种设计思想。先看一下百度百科的解释: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态…...
k8s详解
一、k8s中的yaml文件 JSON格式:主要用于api接口之间信息的传递YAML格式:主要用于配置和管理,YAML是一种简洁的非标记性语言,内容格式人性化 YAML格式: 大小写敏感使用缩进代表层级关系,不支持TAB制表符缩…...
计算机操作系统(第四版)第一章操作系统引论 1.1操作系统的目标和作用
第一章操作系统引论 1.1操作系统的目标和作用 什么是操作系统OS? 配置在计算机硬件上的第一层软件是对硬件的首次扩充。 是最重要的系统软件,其他系统软件应用软件都依赖于操作系统的支持。 操作系统主要作用? 管理计算机系统所有硬件设…...
git push解决办法: ! [remote rejected] master -> master (pre-receive hook declined)
项目经理远程创建了一个空项目,无任何内容,给我赋予的developer账号权限,本地改为后提交代码试了很多次都上传不上去,报错如下: ! [remote rejected] master -> master (pre-receive hook declined)先说结果&#x…...
jQuery 遍历方法总结
遍历方法有:1、add(),用于把元素添加到匹配元素的集合中;2、children(),用于返回被选元素的所有直接子元素;3、closest(),用于返回被选元素的第一个祖先元素;4、contents(),用于返回…...
OKHttp 源码解析(二)拦截器
游戏SDK架构设计之代码实现——网络框架 OKHttp 源码解析(一) OKHttp 源码解析(二)拦截器 前言 上一篇解读了OKHttp 的基本框架源码,其中 OKHttp 发送请求的核心是调用 getResponseWithInterceptorChain 构建拦截器链…...
如何修改设置浏览器内核模式
优先级: 强制锁定极速模式 >手动切换(用户)>meta指定(开发者)>浏览器兼容列表(浏览器) 需要用360安全浏览器14,chromium108内核,下载地址https://bbs.360.cn/t…...
30个Python常用小技巧
1、原地交换两个数字 1 2 3 4 x, y 10, 20 print(x, y) y, x x, y print(x, y) 10 20 20 10 2、链状比较操作符 1 2 3 n 10 print(1 < n < 20) print(1 > n < 9) True False 3、使用三元操作符来实现条件赋值 [表达式为真的返回值] if [表达式] else [表达式…...
ubuntu解决中文乱码
1、查看当前系统使用的字符编码 ~$ locale LANGen_US LANGUAGEen_US: LC_CTYPE"en_US" LC_NUMERIC"en_US" LC_TIME"en_US" LC_COLLATE"en_US" LC_MONETARY"en_US" LC_MESSAGES"en_US" LC_PAPER"en_US" …...
2022年全国职业院校技能大赛(中职组)网络安全竞赛试题——MYSQL安全测试解析(详细)
B-3任务三:MYSQL安全测试 *任务说明:仅能获取Server3的IP地址 1.利用渗透机场景kali中的工具确定MySQL的端口,将MySQL端口作为Flag值提交; 2.管理者曾在web界面登陆数据库,并执行了select <?php echo \<pre>\;system($_GET[\cmd\]); echo \</pre>\; ?…...
C++ map和unordered_map的区别
unordered_map 类模板和 map 类模板都是描述了这么一个对象:它是由 std::pair<const Key, value> 组成的可变长容器; 这个容器中每个元素存储两个对象,也就是 key - value 对。 1. unordered_map 在头文件上,引入 <unor…...
BCSP-玄子JAVA开发之JAVA数据库编程CH-04_SQL高级(二)
BCSP-玄子JAVA开发之JAVA数据库编程CH-04_SQL高级(二) 4.1 IN 4.1.1 IN 子查询 如果子查询的结果为多个值,就会导致代码报错解决方案就是使用 IN 关键字,将 替换成 IN SELECT …… FROM 表名 WHERE 字段名 IN (子查询);4.1.…...
学习java——②面向对象的三大特征
目录 面向对象的三大基本特征 封装 封装demo 继承 继承demo 多态 面向对象的三大基本特征 我们说面向对象的开发范式,其实是对现实世界的理解和抽象的方法,那么,具体如何将现实世界抽象成代码呢?这就需要运用到面向对象的三大…...
初阶数据结构 - 【单链表】
目录 前言: 1.概念 链表定义 结点结构体定义 结点的创建 2.链表的头插法 动画演示 代码实现 3.链表的尾插 动画演示 代码实现 4.链表的头删 动画演示 代码实现 5.链表的尾删 动画演示 代码实现 6.链表从中间插入结点 动画演示 代码实现 7.从单…...
第五周作业、第一次作业(1.5个小时)、练习一
一、创建servlet的过程没有太多好说的,唯一需要注意的就是:旧版本的servlet确实需要手动配置web.xml文件,但是servlet2.5以后,servlet的配置直接在Java代码中进行注解配置。我用的版本就不再需要手动去配置web.xml文件了,所以我只…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
