Python基础:函数式编程
一、概述
Python是一门多范式的编程语言,它同时支持过程式、面向对象和函数式的编程范式。因此,在Python中提供了很多符合 函数式编程 风格的特性和工具。
二、lambda表达式(匿名函数)
除了 函数 中介绍的 def语句,Python还提供了另外一种定义函数的方法: lambda表达式。
lambda表达式的语法如下:
lambda [arguments]: expression
与def语句类似,lambda表达式创建的函数:
- 也是可调用对象(接受0个或多个参数,返回一个值)
- 也是一等公民(first-class)
- 也支持嵌套定义(def中的lambda,或lambda中的lambda)
但是lambda表达式与def语句之间,也存在很多显著的差异:
| 差异点 | 函数(lambda表达式) | 函数(def语句) |
|---|---|---|
| 函数体 | 只能是单行表达式(expression) | 可以是任意复杂的语句(statement) |
| 函数返回值 | 返回值就是函数体中的表达式的求值结果 | 由函数体中的return语句指定 返回值 |
| 函数名 | 定义后直接返回函数对象(匿名函数) | 定义后自动为函数对象绑定函数名 |
| 函数定义位置 | 可以在任何允许函数对象出现的位置定义(支持即时定义,即时调用) | 只能在允许语句出现的位置定义(先定义,后调用) |
| 用途 | 多用于一次性使用的简单函数 | 适用于一切函数和类方法 |
以下是lambda表达式的简单示例:
# def语句
>>> def func(x, y): return x + y # 自动绑定函数名为func
...
>>> func
<function func at 0xb76eff7c>
>>> func(1, 2) # 先定义,后调用
3# lambda表达式
>>> lambda x, y: x + y # 匿名函数(直接返回函数对象)
<function <lambda> at 0xb76ef0d4>
>>> (lambda x, y: x + y)(1, 2) # 即时定义,即时调用
3
>>> f = lambda x, y: x + y # 手动绑定函数名
>>> f(1, 2) # 也可以先定义,后调用
3
>>>
>>> ((lambda x: (lambda y: x + y))(1))(2) # 嵌套定义的lambda(较复杂,尽量避免)
3
三、内建函数filter()、map()、reduce()
1、filter()
函数原型:filter(function, iterable)
说明:返回一个由iterable中的某些元素组成的列表,这些元素使得function返回True。若iterable为字符串(或元组),则返回字符串(或元组);否则,总是返回列表。如果function为None,则默认为恒等函数(identity function,类似 f(x) = x)。
示例:
# for循环版本
>>> res = []
>>> for x in 'a1b2c3d4e5f6':
... if x.isalpha():
... res.append(x)
...
>>> res
['a', 'b', 'c', 'd', 'e', 'f']# filter版本
s = 'a1b2c3d4e5f6'
>>> filter((lambda x: x.isalpha()), s) # iterable为字符串,则返回字符串
'abcdef'
>>> filter((lambda x: x.isalpha()), tuple(s)) # iterable为元组,则返回元组
('a', 'b', 'c', 'd', 'e', 'f')
>>> filter((lambda x: x.isalpha()), list(s)) # iterable为其他迭代对象,则返回列表
['a', 'b', 'c', 'd', 'e', 'f']
>>> filter(None, list(s)) # function为None,则默认为恒等函数
['a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6']
2、map()
函数原型:map(function, iterable, ...)
说明:逐个以iterable中的元素为参数调用function,并返回结果的列表。如果存在多个iterable,则以最长的为准(其他不足的补None),逐个并行取出元素作为参数调用function(如map(function, iter1, iter2)会返回列表[function(iter1[0], iter2[0]), function(iter1[1], iter2[1]), ...])。如果function为None,则默认为恒等函数。
示例:
# for循环版本
>>> res = []
>>> for x in [1, 2, 3, 4, 5]:
... res.append(x ** 2)
...
>>> res
[1, 4, 9, 16, 25]# map版本
>>> map((lambda x: x ** 2), [1, 2, 3, 4, 5])
[1, 4, 9, 16, 25]
>>> map(None, [1, 2, 3, 4, 5]) # function为None,则默认为恒等函数
[1, 2, 3, 4, 5]
>>> map((lambda x, y: x + y), [1, 2, 3], [4, 5, 6]) # 存在多个iterable,则返回[1+4, 2+5, 3+6]
[5, 7, 9]
>>> map(None, [1, 2, 3], [4, 5]) # 以最长的iterable为准,其他不足的补None
[(1, 4), (2, 5), (3, None)]
3、reduce()
函数原型:reduce(function, iterable[, initializer])
说明:以累加方式逐个取出iterable中的元素作为参数调用(具有双参数的)function,从而最终将iterable简化为一个值(如reduce(function, [1, 2, 3])会返回function(function(1, 2), 3))。如果存在initializer,则在累加调用中,以它作为初始的第一个参数。function必须是可调用对象(不能为None)。
示例:
# for循环版本
>>> total = 0
>>> for x in [1, 2, 3, 4, 5]:
... total += x
...
>>> total
15# reduce版本
>>> reduce((lambda x, y: x + y), [1, 2, 3, 4, 5]) # 相当于((((1+2)+3)+4)+5)
15
>>> reduce((lambda x, y: x + y), [1, 2, 3, 4, 5], 10) # 带有initializer的reduce,相当于(((((10+1)+2)+3)+4)+5)
25
>>> sum([1, 2, 3, 4, 5], 10) # 等效于上面的reduce
25
四、闭包
闭包(closure)是一个内嵌函数,它能够记住其 外围作用域 中的所有名字,即使这个作用域 看起来 已经不在外围。
在以下示例中,内嵌函数action就是一个闭包:
>>> def maker(N):
... def action(x):
... return x * N
... return action
...
>>> mul10 = maker(10)
>>> mul10(3)
30
>>> mul10(5)
50
尽管函数调用mul10 = maker(10)已经返回并退出了,但后续的mul10却能够记住整数10,从而计算入参的10倍数。
实际上,外围作用域(如函数maker对应的代码范围)中的所有名字(如参数N)都作为环境信息被绑定到了action函数上,因此每次调用action时都可以访问这些环境信息。特别地,可以通过特殊属性func_closure来获取一个函数的自由变量绑定:
>>> def maker(N):
... def action(x):
... return x * N
... print(action.func_closure) # 打印出action函数的func_closure属性值
... return action
...
>>> N = 10
>>> print('int N: id = %#0x, val = %d' % (id(N), N)) # N的值为10(整数10的地址是0x8e82044)
int N: id = 0x8e82044, val = 10
>>> mul10 = maker(N) # action.func_closure中含有整数10(即自由变量N)
(<cell at 0x90e96bc: int object at 0x8e82044>,)
闭包的这种 能够记住环境状态 的特性非常有用,Python中有一些其他特性就是借助闭包来实现的,比如 装饰器。
五、偏函数应用
1、基本用法
偏函数应用(Partial Function Application)是一种简化函数调用的方式,主要表现为对函数的部分参数进行固化。
Python中的偏函数应用是借助 functools.partial 来完成的。例如有一个专用于生成文章标题的函数title:
>>> def title(topic, part):
... return topic + u':' + part
...
如果要为python基础系列的多篇文章生成标题,可以有以下两种方式:
# 普通版本
>>> print title(u'Python基础', u'开篇')
Python基础:开篇
>>> print title(u'Python基础', u'函数')
Python基础:函数
>>> print title(u'Python基础', u'函数式编程')
Python基础:函数式编程# 偏函数版本
>>> from functools import partial
>>> pybasic_title = partial(title, u'Python基础')
>>> print pybasic_title(u'开篇')
Python基础:开篇
>>> print pybasic_title(u'函数')
Python基础:函数
>>> print pybasic_title(u'函数式编程')
Python基础:函数式编程
从上面的示例可以看出,如果在编码过程中遇到了“多次用相同的参数调用一个函数”的场景,就可以考虑使用偏函数来固化这些相同的参数,进而简化函数调用。
2、等效实现
1)默认参数
在上述示例中,如果将函数title的定义改为def title(part, topic=u'Python基础')也可以达到相同的效果。但是这种方式的不足之处也很明显:
- 需要修改已有函数title的定义
- 默认参数只能有一个固定值,定义后即不能更改
相比之下,偏函数具有很好的灵活性:既不用修改已有函数的定义,又可以为函数的参数固化不同的值。
2)lambda表达式
使用 lambda表达式 也可以实现类似偏函数的功能,并且与默认参数不同的是,可以针对不同的参数值定义不同的lambda表达式(因为lambda表达式通常是一次性使用的)。例如上述示例中的pybasic_title也可以实现为:
>>> pybasic_title = (lambda part: u'Python基础:' + part)
>>> print pybasic_title(u'开篇')
Python基础:开篇
>>> print pybasic_title(u'函数')
Python基础:函数
>>> print pybasic_title(u'函数式编程')
Python基础:函数式编程
但是,由于lambda表达式本身的限制(参考 『lambda表达式』 一节),在具有复杂函数的场景中,还得使用偏函数。
3)闭包
最后,使用 闭包 同样可以等效地实现偏函数的功能,并且与lambda表达式不同的是,它没有任何限制场景。还是上面的例子:
>>> def title(topic):
... def topic_title(part):
... return topic + u':' + part
... return topic_title
...
>>> pybasic_title = title(u'Python基础')
>>> print pybasic_title(u'开篇')
Python基础:开篇
>>> print pybasic_title(u'函数')
Python基础:函数
>>> print pybasic_title(u'函数式编程')
Python基础:函数式编程
可以看出,这个闭包版本的唯一缺点是它需要对函数title进行重新定义(与默认参数的情况有些类似)。
总而言之,如果需要对 已有函数 进行参数固化,偏函数是最佳选择。
六、列表解析
这里主要强调两点:
- 列表解析可以用来代替上面提到的一些函数式编程方法
- 列表解析还有一个生成器版本的近亲:生成器表达式
1、用列表解析代替filter()和map()
1)filter()
列表解析可以完全代替filter():
- function不为None时:
[item for item in iterable if function(item)]等价于filter(function, iterable) - function等于None时:
[item for item in iterable if item]等价于filter(None, iterable)
2)map()
在以下情况中,列表解析可以代替map():
- 只有一个iterable时
- function不为None:
[function(item) for item in iterable]等价于map(function, iterable) - function等于None:
[item for item in iterable]等价于map(None, iterable)
- function不为None:
- 多个iterable长度相同时
- function不为None:
[function(*args) for args in zip(iter1, iter2, ...)]等价于map(function, iter1, iter2, ...) - function等于None:
zip(iter1, iter2, ...)等价于map(None, iter1, iter2, ...)
- function不为None:
如果多个iterable具有不同的长度,那么列表解析就无法代替map()了。
2、生成器表达式
生成器表达式(Generator Expressions)与列表解析在语法和功能方面都非常相似。二者的根本差异是:生成器表达式返回一个 生成器,而列表解析返回一个列表。如下所示:
| 差异点 | 生成器表达式 | 列表解析 |
|---|---|---|
| 表示方法 | (expr for item in iterable if cond_expr) | [expr for item in iterable if cond_expr] |
| 返回值 | 一个生成器 | 一个列表 |
与列表解析相比,生成器表达式具有 延迟计算(lazy evaluation)的特点,因此在使用内存上更有效。
相关文章:
Python基础:函数式编程
一、概述 Python是一门多范式的编程语言,它同时支持过程式、面向对象和函数式的编程范式。因此,在Python中提供了很多符合 函数式编程 风格的特性和工具。 二、lambda表达式(匿名函数) 除了 函数 中介绍的 def语句,P…...
【YBT2023寒假Day14 C】字符串题(SAM)(树链剖分)(线段树)
字符串题 题目链接:YBT2023寒假Day14 C 题目大意 对于一个字符串 S 定义 F(S) 是 fail 树上除了 0 点其它点的深度和。 G(S) 是 S 每个子串 S’ 的 F(S’) 之和。 然后一个空串,每次在后面加一个字符,要你维护这个串的 G 值。 思路 考虑…...
Tailwind CSS 在Vue中的使用
什么是Tailwind CSS? Tailwind CSS 是一个功能类优先的 CSS 框架,它集成了诸如 flex, pt-4, text-center 和 rotate-90 这样的的类,支持 hover 和 focus 样式,它们能直接在脚本标记语言中组合起来,构建出任何设计。 …...
三层楼100人办公网络如何规划设计实施(实战案例)
如何设计组网 1.采用防火墙+三层交换机+二层POE交换机+AP的方案 2.三层交换机作为网络的核心,提供网络的配置、划分和各个VLAN间的数据交换,而每个VLAN由二层交换机组建 3.网络主干设备的选型,建议网络主干设备或核心层设备选择具备第3层交换功能的高性能主干交换机。 4…...
Redis:实现全局唯一ID
Redis:实现全局唯一ID一. 概述二. 实现(1)获取初始时间戳(2)生成全局ID三. 测试为什么可以实现全局唯一?其他唯一ID策略补充:countDownLatch一. 概述 全局ID生成器:是一种在【分布式…...
webpack打包基本原理——实现webpack打包核心功能
webpack打包的基本原理 核心功能就是把我们写的模块化代码转换成浏览器能够识别运行的代码,话不多说我们一起来了解它 首先我们建一个空项目用 npm init -y 创建一个初始化的,在跟目录下创建src文件夹,src下创建index.js,add.js…...
git的使用(终端输入指令) 上
git目录前言1.创建仓库2.创建文件和修改数据状态分区3 .删除、撤销重置 、和比较前言 今天带大家手把手敲一遍 git 流程: 安装一下git(详细观看我之前发的git文档࿰…...
react定义css样式,使用less,css模块化
引入外部 css文件 import ./index.css此时引入的样式是全局样式 使用less 安装 npm i style-loader css-loader sass-loader node-sass -D生成config文件夹 npm run eject配置 以上代码运行完,会在根目录生成config文件夹 进入 config > webpack.config.js 查找…...
基于JavaWeb的学生管理系统
文章目录 项目介绍主要功能截图:登录用户信息管理院系信息管理班级信息管理新增学生课程管理成绩管理部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系�…...
win11右键新建菜单添加选项
需要操作 2 处注册表, 以下以在右键新建菜单中添加 .html 为例 在主键 HKEY_CLASSES_ROOT 中,搜索 .html 找到后 ,右键点击它,选 新建 ->项, 在这里插入图片描述 项目名字是:ShellNew 新建后&#x…...
leetcode Day5(卡线复试,放弃版)
Day5 最后一个单词长度(要求最后一个,可以反向计数) int lens.length()-1; while(s.charAt(len)){len--;//最后是一个空格,就是无字符时 } int wordlen0;//记录字符长度 /*charAt() 方法用于返回指定索引处的字符。索引范围为从 0…...
cmake 入门二 库的编译,安装与使用
工程描述 1,建立一个静态库和动态库,提供HelloFunc 函数供其他程序编程使用,HelloFunc 向终端输出Hello World字符串。 2,安装头文件与共享库。 1 库的工程结构 1.1 工程目录下的CMakeLists.txt PROJECT…...
Python中实现将内容进行base64编码与解码
一、需求说明需要使用Python实现将内容转为base64编码,解码,方便后续的数据操作。二、base64简介Base64是一种二进制到文本的编码方式【是一种基于 64 个可打印字符来表示二进制数据的表示方法(由于 2^664,所以每 6 个比特为一个单…...
集合TreeSet的使用-java
TreeSet的特点:可排序、不重复、无索引。可排序:按照元素的大小默认升序排序;底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。对于数值、字符串类型的(Integer 、Double、String)TreeSet可以排…...
Mybatis-plus 分页集成以及基本使用总结 入门和案例 注解连表查询分页案例等
简介 Mybaits-plus 是mybits 的升级版,从mybaits 升级到mybaits-plus 可以实现平滑升级 Mybaits-plus 本身提供了大量的基本查询方法以及强大的 Wrapper(包装) 类 用于查询的 QueryWrapper 以及 更新的 UpdateWrapper ,使用Wrapper 基本已经可以构建大…...
5个设计师常用素材库
推荐5个设计素材网站,免费下载! 1、菜鸟图库 菜鸟图库-免费设计素材下载 菜鸟图库是一个素材量非常丰富的网站,该网站聚合了平面、UI、淘宝电商、高清背景图、图片、插画等高质量素材。平面设计模板非常多,很多都能免费下载&…...
PHP/7.2.11 缺少 apache2/logs/httpd.pid 文件
启动服务时:systemctl restart httpd.service,报错:● httpd.service - httpd serviceLoaded: loaded (/etc/systemd/system/httpd.service; enabled; vendor preset: disabled)Active: failed (Result: exit-code) since 五 2023-02-24 16:1…...
【centos7下部署mongodb】
一.安装环境 CentOS7MongoDB4.0.13正式版。 二.下载MongoDB 1.1 官网下载地址:https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.13.tgz 1.2 将压缩包通过xftp上传到服务器/opt目录,然后解压、改名 三. 配置环境变量及配置文件 3.1配置系…...
pycharm首次使用爬虫框架scrapy遇到的问题和解决方法(二)
在首次使用scrapy框架的过程中,一直是对着别人的框架步骤撸代码的。然而,撸着撸着发现好像别人的也用不了。后面就只能自己找踏坑了。 问题报错: 1,IndexError: list index out of range 2,pymysql.err.ProgrammingError: (1064, "You have an error in your SQL s…...
pyflink学习笔记(二):table_apisql
Joins Inner Join 官网说明:和 SQL 的 JOIN 子句类似。关联两张表。两张表必须有不同的字段名,并且必须通过 join 算子或者使用 where 或 filter 算子定义至少一个 join 等式连接谓词。先创建2个表,两个表的字段是相同的,我想验证…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
