Python函数式编程入门窥探

文章目录

  • 函数式编程
    • 把函数当作对象
    • 高阶函数
      • map的替代品
      • reduce的替代品
      • filter的替代品
    • 匿名函数
    • 可以向函数一样可调用的对象
    • 自定义的调用类型
    • 函数内省
    • 传递给函数的参数:从定位参数到仅限关键字参数
    • 获取关于函数参数的信息--inspect模块
      • 获取函数签名的signature方法
      • inspect.Signature对象的bind方法
    • Python3 的一个特性——函数注解
    • 支持函数式编程的包(operator,functools)
      • 另一种冻结参数的方法functools.partial
  • 小结

函数式编程

把函数当作对象

函数式编程是把函数作为一等公民,把一些算数运算符当作函数使用,python不是一门纯粹的函数式编程语言,但是在一些库的加持下(operator,functools)使得他的函数式编程功能同样强大

在python中我们会把函数当作对象使用

def foo(x):"""x * x * x"""return x * x * xprint(foo(3))
print(foo.__doc__) # python 中的一种特殊方法用于查看函数的注解

高阶函数

在其他语言的函数式编程中经常使用map,reduce在python中也可以使用,不过python对着两种方法都有更便捷的实现方式

map的替代品

map方法可以应用python的列表表达式得到更简便更可读的实现

# map 和 列表表达式
def square(x):return x * x
square_one_to_ten = map(square,range(1,11))print(list(square_one_to_ten))square_one_to_ten = [square(i) for i in range(1,11)]
print(square_one_to_ten)
# 输出
c:/Users/Administrator/GithubRepo/study_recording/fluent_python/ch05/test_case.py
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

reduce的替代品

reduce方法在python3之后就被移除了内置方法,我们可以在functools中找到这个函数,我们可以使用python中的sum()方法作为替代品,而且sum方法的效率更加高效

# reduce 和 sum
# 计算累计求和
from functools import reduce
from operator import  add
acumulation = reduce(add , range(0,100))# 0 - 99 sum
new_trick = sum(range(0,100))
print(acumulation == new_trick) # True

sum 和 reduce 的特点是应用某一种操作到指定序列上,累计之前的结果,把一个系列值归约成一个值
除此之外 python 中的all()和any()方法也是一种归约函数,前者是只要序列中都不为0返回True后者是只要有真值就返回True

filter的替代品

过滤一些序列中的元素我们同样可以用列表表达式来实现

# filter and list generator
format1 = filter(lambda x : x % 2 == 0,range(11))
format2 = [i for i in range(11) if i % 2 == 0]print(f'user filter : {list(format1)}\nuse list generator : {format2}')
# 输出
# user filter : [0, 2, 4, 6, 8, 10]
# use list generator : [0, 2, 4, 6, 8, 10]

同样的结果我们可以使用列表表达式来减少lambda函数的使用

匿名函数

python中的匿名函数无法对传入的变量进行赋值,它只能是纯表达式的形式
除了作为参数传递给一些高阶函数,平凡的lambda函数容易写出,难的lambda表达式就难以阅读

可以向函数一样可调用的对象

python中判断一个对象是否可以被调用,可以调用其内置的callable()方法

# callable
from operator import add
print([callable(i) for i in [add, str , 1]]) # [True, True, False]

自定义的调用类型

在python中一切皆为对象,不仅函数可以表现得像对象,甚至对象也可以表现得像函数,我们只需要去实现python对象中的__call__这个实例方法

# callable object
import randomclass RandomNumberSelector():def __init__(self) -> None:self._item = list(range(100))random.shuffle(self._item)def __call__(self):return self._item[random.randint(0,100)]obj = RandomNumberSelector()
print(obj())
print(obj())

函数内省

除了__call__和__doc__函数还有其他很多的属性,使用dir方法可以了解一个函数还有那些属性

print([i for i in dir(square)])
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', 
'__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

我们也可以了解对象有哪些属性

print([i for i in dir(RandomNumberSelector)])
['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

同时我们也可以查看二者不共存的属性

print(sorted(set(dir(square)) - set(dir(RandomNumberSelector))))
['__annotations__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']

以上是类的属性中没有而函数属性有的属性

我们主要介绍与把函数视为对象的一些方法比如__dict__属性,是一种为函数提供注解的属性,Django框架中对函数赋予了这种注解的属性

传递给函数的参数:从定位参数到仅限关键字参数

python提供了及其灵活的参数处理方式,python3又提供了一种仅限关键字参数,同时密切相关的有*和**符号,可以展开可迭代对象这个过程就是拆包的过程
*符号,会把没有明确指定名称关键字的参数捕获作为列表传入,**符号会把没有明确指定名称的关键字参数捕获作为字典输入函数

# Example
def tag(name,*content,cls=None,**attrs):"""生成一个或者多个HTML标签"""if cls is not None:attrs['class'] = clsif attrs :attrs_str = ' '.join('%s="%s"' % (attr,value)for attr , valuein sorted(attrs.items()))else :attrs_str = ''if content:return '\n'.join('<%s %s>%s</%s>' % (name , attrs_str , c ,name) for c in content)else :return '<%s%s />' % (name , attrs_str)print(tag("br"))
print(tag("p","hello","world!"))
print(tag("h1","hello world!"))
print(tag('div',"FOo",cls="frame",id="dow")) # cls只能作为关键字参数传入
print(tag('div',"FOo",id="dow"))

输出 :

<br />
<p >hello</p>
<p >world!</p>
<h1 >hello world!</h1>
<div class="frame"id="dow">FOo</div>
<div id="dow">FOo</div>

获取关于函数参数的信息–inspect模块

函数对象具有__default__属性,其值是一个元组,保存着定位参数和关键字参数的默认值,仅限关键字参数的默认值存放在__kwdefaults__属性中,参数的名称存放在__code__属性中,其是一个code对象的引用,本身也有很多属性

# Example
def clip(text,max_len=80):"""在max_len前面或者后面的第一个空格处截断文本"""end = Noneif len(text) > max_len:space_before = text.rfind(' ',0,max_len) # rfind函数的第二个参数beg规定从哪里开始搜索,如果不设置则默认从尾部开始搜索if space_before >= 0:end = space_beforeelse :space_after = text.rfind(' ',max_len)if space_after >= 0 :end = space_afterif end is None:end = len(text)return text[:end].rstrip() # 去掉右边的空格部分

获取函数签名的signature方法

from inspect import signature
sig = signature(clip)print(sig) # 输出 : (text, max_len=80)for name, param in sig.parameters.items():print(f'name:{name} ,param:{param}')# name:text ,param:text# name:max_len ,param:max_len=80

signature方法返回了一个inspect.Signature对象,它有一个paramerters属性,对应了一个有序映射,是字典。把参数的名字和inspect.Parameter对象对应起来,每个Parameter都有自己的属性

inspect.Signature对象的bind方法

sig = signature(tag)
my_tag = {"name":'p',"content":["Hello","World!"],"cls":'news',"attrs":{"id":1}}
bound_args = sig.bind(**my_tag)
print(bound_args)
# <BoundArguments (name='p', cls='news', attrs={'content': ['Hello', 'World!'], 'attrs': {'id': 1}})>
for name,value in bound_args.arguments.items():print(name , value)
# name p
# cls news
# attrs {'content': ['Hello', 'World!'], 'attrs': {'id': 1}}

Signature对象有一个bind方法可以把任意个参数绑定到签名中的形参上,这里通过输入可以发现,当输入的形参含有序列信息的时候,这个方法会把序列信息给**attrs参数捕获,存入一个字典

Python3 的一个特性——函数注解

python3可以在函数声明和返回值附加元数据

def func(foo:str) -> int:return int(foo)

这种注解不会对函数做任何处理,只会存储在__annotations__属性中(一个字典)

for k , v in func.__annotations__.items():print(f'{k} = {v}')
# foo = <class 'str'>
# return = <class 'int'>

支持函数式编程的包(operator,functools)

函数式编程中经常需要把算术运算符当作函数使用,operator包提供了完整的算术运算符的函数

使用operator中的mul,add,配合reduce可以实现累乘或者累加

例如使用mul函数来实现阶乘

from operator import mul
from functools import reduce
def fact(n):return reduce(mul,range(1,n+1))

operator库中除了有算数运算符还有一些能从序列中读取对象属性的方法,分别是itemgetter和attrgetter顾名思义分别是读取对象索引和读取对象参数,本质上是一些简单lambda表达式的更有可读性的实现

operator中余下的模块中还有一个methodcaller方法,适用于对一个对象使用指定参数的方法

s = 'upper these characters'
from operator import methodcaller
uppercase = methodcaller('upper')
s = uppercase(s)
print(s) # UPPER THESE CHARACTERSreplace_backspace = methodcaller('replace',' ','___')
s = replace_backspace(s)
print(s) # UPPER___THESE___CHARACTERS

最后一个print可以发现methodcaller还有冻结部分参数的功能

另一种冻结参数的方法functools.partial

冻结参数的本质其实就是将一个函数的部分参数应用于一个对象

from functools import partial
from operator import mulmultiply_3 = partial(mul,3)
print(multiply_3(21)) # 63

partial的第一个参数是要可执行的一个方法,后面紧跟的是关键字参数或者不定参数

小结

Python本身不是一门函数式编程语言,但是它参考了一些函数式编程语言很好的地方,除了可以写出更可读的代码外。还能用它来实现一些特定功能,本身也提供了强大的注解系统和函数和对象之间的灵活调用

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【智能家居入门1】环境信息监测(STM32、ONENET云平台、微信小程序、HTTP协议)

作为入门本篇只实现微信小程序接收下位机上传的数据&#xff0c;之后会持续发布如下项目&#xff1a;①可以实现微信小程序控制下位机动作&#xff0c;真正意义上的智能家居&#xff1b;②将网络通讯协议换成MQTT协议再实现上述功能&#xff0c;此时的服务器也不再是ONENET&…

解决Springboot服务启动报错:“Reason: Failed to determine suitable jdbc url”

1、错误详情 *************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: url attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine sui…

C语言之指针详解(4)

文章目录 一、回调函数二、qsort使用举例2.1使用qsort函数排序整型数据2.2使用qsort函数排序结构体数据 三、qsort函数的模拟实现 一、回调函数 首先我们先来了解一下什么是回调函数 回调函数通俗来讲就是一个通过函数指针调用的函数。 如果你把函数的指针&#xff08;地址&am…

【微服务】本地事务和远程调用的执行先后关系以及带来的风险和解决方案

前言 在做订单模块的时候&#xff0c;本地事务中包含了远程调用&#xff0c;引发一些问题&#xff0c;这里做一次简单的复盘。 1、问题复现 首先下完订单&#xff0c;调用支付服务成功&#xff0c;然后支付服务收到微信的回调&#xff0c;然后通知我支付结果 但是我的支付回…

canvas层级太高?解决方法

这个方法主要是依赖于邀请好有页面展示的canvas二维码二维码以及其他容器的图片 有一个保存图片功能&#xff0c;这个保存图片是需要将二维码以及涉及到的其他容器比如下图&#xff1a; 所以这时候需要canvas来绘制一个保存图片的效果&#xff0c;然后对这个canvas绘制的图片保…

web网络安全知多少

web安全性包括: 客户端脚本安全和服务器端应用服务器 客户端脚本安全: ● 跨站脚本攻击(XSS ) ● 跨站点请求伪造(CSRF) ● 点击劫持(ClickJacking) ● HTML 5 安全性 服务端应用安全: ● 注入攻击 ● 文件上传漏洞 ● 认证与会话管理 ● 访问控制 ● DDos攻击 个人意识和个人…

【CALayer-时钟练习-界面-锚点 Objective-C语言】

一、接下来,我们来说这个时钟练习 1.这个里边呢,有这么一个表盘的一个效果,然后呢,这个秒针,跟我们的时间,是同步的, 新建一个项目, Name:05-时钟练习 然后呢,给这个控制器的View,一个背景颜色,先, 背景颜色, 2.接下来,我们开始来做,我们现在这个表盘啊,是我们…

关于前端项目依赖的node版本冲突的问题

最近在几个不同的项目切换 有老的项目有新的项目 当中所需要的node版本冲突 苦思半天后好像有个简单的办法来进行解决node 冲突的问题 1&#xff1a;更改项目配置文件 在package.json中增加对应的node版本 当前项目就不会出现版本过高的语法无法使用的问题 视乎是一个比较方…

绿色瓶装水“暗战”竞争越发激烈,华润饮料谋上市同时多地扩产能

《港湾商业观察》黄懿 4月23日&#xff0c;纯净水牌“怡宝”母公司华润饮料&#xff08;控股&#xff09;有限公司&#xff08;下称“华润饮料”&#xff09;向港交所主板提交上市申请&#xff0c;联席保荐人为中银国际、中信证券、美银美林、瑞银集团。 在华润饮料递表不久之…

【ARM+Codesys案例】基于全志T3+Codesys软PLC的3C点胶边缘控制解决方案:整合了运动控制、视觉、激光测高等技术

视觉精密点胶控制方案 针对直交型机构的平面点涂胶应用&#xff0c;基于CODESYS软件平台开发的一站式PC型控制器解决方案&#xff0c;包含运动控制器硬件和点胶应用软件。方案整合了运动控制、视觉、激光测高等技术&#xff0c;高效精密的控制胶水点涂于产品表面或内部&#x…

聊一聊开发语言的基础控制结构

一、描述下for循环、while循环和do-while循环的区别和用法。 在编程中&#xff0c;for循环、while循环和do-while循环是用于重复执行一段代码直到满足特定条件的控制结构。每种循环都有其特定的用途和语法。以下是它们之间的区别和用法&#xff1a; 1. for循环 用法&#xf…

Mac上安装harbor

在Mac Book VMware Fusion 虚拟出来的 ubuntu&#xff08;22.04.4&#xff09;的环境中安装官方离线版本 harbor-offline-installer-v2.10.2.tgz会出现如下错误&#xff1a; prepare base dir is set to /home/zhangzk/harbor WARNING: The requested images platform (linux/…

CHIMA专访美创高级总监丁斐:为医疗数据安全构筑体系化防御新机制

5月17-19日&#xff0c;中国医院信息网络大会&#xff08;CHIMA 2024&#xff09;在南京隆重召开。作为结识多年的老友&#xff0c;美创科技再携以数据为中心的全系列安全业务、新一代数字化安全平台、医疗行业解决方案精彩亮相。 会议期间&#xff0c;CHIMA专访美创科技&…

[数据集][目标检测]RSNA肺炎检测数据集VOC+YOLO格式6012张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6012 标注数量(xml文件个数)&#xff1a;6012 标注数量(txt文件个数)&#xff1a;6012 标注…

聊天室概述,什么是聊天室呢?

聊天室&#xff08;Chatroom&#xff09;提供了支持高并发消息处理的业务形态&#xff0c;可用于直播、社区、游戏、广场交友、兴趣讨论等场景。App Key 下可创建的聊天室数量没有限制&#xff0c;单个聊天室成员数量没有限制。 服务配置 聊天室不需要申请开通。聊天室的部分…

【基础算法总结】前缀和二

前缀和二 1.和为 K 的子数组2.和可被 K 整除的子数组3.连续数组4. 矩阵区域和 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.和为 K 的子数…

Java语言ADR药物不良反应系统源码Java+IntelliJ+IDEA+MySQL一款先进的药物警戒系统

Java语言ADR药物不良反应系统源码JavaIntelliJIDEAMySQL一款先进的药物警戒系统源码 ADR药物不良反应监测系统是一个综合性的监测平台&#xff0c;旨在收集、报告、分析和评价药品在使用过程中可能出现的不良反应&#xff0c;以确保药品的安全性和有效性。 以下是对该系统的详细…

Modbus工业网关

随着工业自动化程度的不断提高&#xff0c;设备之间的数据通信与交互变得至关重要。在这一背景下&#xff0c;Modbus协议凭借其简单、可靠、开放的特点&#xff0c;成为了工业自动化领域中最常用的通信协议之一。而HiWoo Box网关作为一款支持Modbus协议的工业网关设备&#xff…

tomcat启动流程

在Tomcat中,每个组件都扮演着不同的角色,共同协作以提供Web服务。以下是对Tomcat中主要组件及其作用的详细解释: Server 作用:Server是Tomcat的顶级组件,代表Tomcat的运行实例。 特点:一个Tomcat服务器只有一个Server组件,它包含Global Naming Resources组件以集成JND…

【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP和Uniapp)

一款基于FastAdminThinkPHP和Uniapp进行开发的多平台&#xff08;微信小程序、H5网页&#xff09;溯源、防伪、管理一体化独立系统&#xff0c;拥有强大的防伪码和溯源码双码生成功能&#xff08;内置多种生成规则&#xff09;、批量大量导出防伪和溯源码码数据、支持代理商管理…