【Python专题】函数式编程
注:本系列内容系廖雪峰大神python教程的学习笔记
本文主要讲解了python中函数式编程的相关内容,包括:
- 高阶函数
- mapreduce
- filter
- sorted
- 返回函数
- 匿名函数
- 装饰器
- 偏函数
1.高阶函数
高阶函数指的是函数内部接收另一个函数作为参数。
我们来看这样一个例子:求绝对值之和
def abs(x):if x>=0:return xelse:return -xdef sum_abs(x,y,f):return f(x)+f(y)
我们来进行测试:
>>> def sum_abs(x,y,f): ... return f(x)+f(y) ... >>> sum_abs(-5,5,abs) 10
高阶函数的作用主要就是为了将函数作为参数使用。实际上,函数的名称本身也是一个变量,一个指向函数体的变量,如:
>>> f=abs >>> f(-10) 10
2.map/reduce
Python内建了
map()
和reduce()
函数。关于这两个函数的详细情况,请参考Google的map\reduce。map的使用示例:假设现在你要对
List[1,2,3,4,5,6,7,8,9]
进行f(x)=x2f(x)=x^2操作,一般的,你可以通过循环实现它>>> L=[x for x in range(1,11)] >>> L [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> LL=[] >>> for x in L: ... LL.append(x*x) ... >>> LL [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
但是,更为简便的是推荐
map()
方法:>>> def f(x): ... return x*x ... >>> LL=map(f,L) >>> list(LL) [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
可见使用map可以将
f()
函数作用于全体List对象。map返回的是一个Itertor
,因而我们需要使用list将其全部序列计算出来并返回一个list。reduce()
把一个函数作用在一个序列[x1,x2,x3,...,xn]
上,这个函数接收两个参数,reduce
把结果继续和序列的下一个元素做累计计算,结果如下:reduce(f,[x1,x2,x3,x4])=f(f(f(x1,x2),x3),x4)
示例1:序列求和
>>> from functools import reduce >>> def add(x,y): ... return x+y ... >>> reduce(add,[1,2,3,4,5,6,7,8,9,10]) 55
示例2:把序列
[1,3,5,7,9]
变换为整数13579>>> def trans(x,y): ... return x*10+y ... >>> reduce(trans,[1,3,5,7,9]) 13579
综合应用1:写一个函数实现
str
转换为int
>>> def list2int(x,y): ... return x*10+y ... >>> def char2int(s): ... return{'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s] ... >>> def str2int(s): ... return reduce(list2int,list(map(char2int,s))) ... >>> str2int('1234567890') 1234567890
综合应用2:写一个函数把用户输入不规范的英文名改为首字母大写其余小写的规范写法
>>> def normalize(s): ... return s[0].upper()+s[1:].lower() ... >>> list(map(normalize,['adam','LISA','barT'])) ['Adam', 'Lisa', 'Bart']
3.filter
Python 内建的
fileter()
函数用于过滤序列。filter
函数需要传入两个参数:一个函数和一个序列,其把函数作用于序列中的每个数,然后根据返回值保留返回True
的数而删除返回False
的数。示例1:删除一个序列中的偶数
>>> def isodd(x): ... return x%2==1 ... >>> list(filter(isodd,[1,2,3,4,5,6,7,8,9])) [1, 3, 5, 7, 9]
示例2:删除一个序列中的空字符串
>>> def not_empty(s): ... return s and s.strip() ... >>> list(filter(not_empty,['a',' ','AS',None,' ','/'])) ['a', 'AS', '/']
综合应用:用埃式筛法求素数
首先,构造一个从3开始的奇数序列
>>> def _odd_iter(): ... n=1 ... while True: ... n=n+2 ... yield n ...
其次定义一个筛选函数
>>> def _not_divisiable(n): ... return lambda x:x%n>0 ...
定义一个生成器,用以不断产生素数
>>> def primes(): ... yield 2 ... it=_odd_iter() ... while True: ... n=next(it) ... yield n ... it=filter(_not_divisiable(n),it) ...
最后,我们来测试
>>> L=[] >>> for n in primes(): ... if n<1000: ... L.append(n) ... else: ... break ... >>> L [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
4.sorted
排序是程序中经常使用的算法,python内置了
sorted
函数已实现排序算法。对
list
进行排序>>> sorted([12,-12,32,45,67,-1212]) [-1212, -12, 12, 32, 45, 67]
sorted
函数也是一个高阶函数,他可以额外接受一个key
函数来实现自定义排序,如按照绝对值排序>>> sorted([12,-12,32,45,67,-1212],key=abs) [12, -12, 32, 45, 67, -1212]
对字符串排序时按照首字母的ASCII码值进行排序
>>> sorted(['bob','about','Zoo','Credit']) ['Credit', 'Zoo', 'about', 'bob']
如果要实现忽略大小写的排序,则可以这样写
>>> sorted(['bob','about','Zoo','Credit'],key=str.lower) ['about', 'bob', 'Credit', 'Zoo']
当要进行反向排序时,可以传入第三个参数
reverse=True
>>> sorted(['bob','about','Zoo','Credit'],key=str.lower,reverse=True) ['Zoo', 'Credit', 'bob', 'about']
实例:对以下list实现按照名字排序
L=[('Bob',75),('Adam',99),('Bart',87),('Lisa',89),('Lucy',67),('Nancy',100)]
>>> def getName(name): ... return [s[0] for s in name] ... >>> sorted(getName(L),key=str.lower) ['Adam', 'Bart', 'Bob', 'Lisa', 'Lucy', 'Nancy']
5.返回函数
高阶函数除了可以接收函数作为参数外,还可以把函数作为结果值返回。
示例:来实现这样一个操作:写一个可变参数求和函数
>>> def calc_sum(*args): ... ax=0 ... for n in args: ... ax=ax+n ... return ax ...
但是在某些情况下,函数并不需要立刻进行求和,而是在后面的使用中再进行计算,这时,就可以不返回计算的结果,而是返回求和的函数
>>> def lazy_sum(*args): ... def sum(): ... ax=0 ... for n in args: ... ax=ax+n ... return ax ... return sum ...
调用上面的
lazy_sum()
时,返回sum()
函数>>> f=lazy_sum(1,3,5,6,7,9) >>> f <function lazy_sum.<locals>.sum at 0x00000295A6FC6048>
调用这个返回的函数,才进行计算
>>> f() 31
上面的程序中,
sum()
函数定义在lazy_sum()
的内部,但是其却可以引用外部函数lazy_sum()
的参数和局部变量,当lazy_sum()
返回函数sum()
时,相关参数和变量都保存在返回的函数中,这种程序结构称为:闭包(Closure
)闭包:注意,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用。返回的函数没有被立即执行,直到调用返回的函数时才被执行,来看一个例子
>>> def count(): ... fs=[] ... for i in range(1,4): ... def f(): ... return i*i ... fs.append(f) ... return fs ... >>> f1,f2,f3=count() >>> f1() 9 >>> f2() 9 >>> f3() 9
按理,不是应该为
1 4 9
吗,为何都为9
呢?结合上面的说明,我们来进行分析,在执行for
循环时,流程如下:i=1
:def f():return i*i
关键就在这,此时
f()
的返回值是多少呢?你可能觉得应该是:1*1
,但请注意:返回的是函数,也就是i*i
本身,此时结果并未被计算出来,并且,此时的i
还会被后面的函数引用。i=2
def f():return i*i
同理:
i=3
def f():return i*i
注意,上面的三个函数并非同一个,而是相互独立的,但是,内部的变量却是同一个,都是母函数
count()
的变量,那么,当调用这三个函数时,发生了什么?>>> f1,f2,f3=count()
此时上面的三个函数会被依次执行,但是,执行时已经有
i=3
,所以结果都为:9请记住:返回闭包时,不要让返回函数引用任何循环变量,或者是后续会发生变化的变量。
6.匿名函数
在传入函数时,若不需要显示的定义函数,则可以考虑使用匿名函数。
示例:对
list
进行x*x
操作>>> list(map(lambda x:x*x,[1,2,3,4,5,6,7,8,9])) [1, 4, 9, 16, 25, 36, 49, 64, 81]
此时,
lambda x:x*x
其实就是替代了f()
函数def f(x):return x*x
lambda x:x*x
属于匿名函数,关键字lambda
表示匿名函数,冒号前面的x
表示函数的参数而冒号后面的表达式就是匿名函数的返回结果。匿名函数只能有一个表达式。匿名函数可以进行赋值,比如
>>> f=lambda x:x*x >>> f <function <lambda> at 0x00000295A6FC6378> >>> f(5) 25
匿名函数也可以作为函数进行返回
>>> def build(x,y): ... return lambda:x*x+y*y ... >>> f=build(3,4) >>> f() 25
7.装饰器
在某些特殊的情况下,希望在代码运行期间动态的为函数增加功能但又不修改原函数,这种方式即为:装饰器(
Decorator
)示例:现在,我们需要在调用一个函数时让函数自动打印调用信息
先来定义一个打印调用函数的装饰器
>>> def log(func): ... def wrapper(*args,**kw): ... print('calls %s():' % func.__name__) ... return func(*args,**kw) ... return wrapper ...
上面的
log()
函数接收一个函数参数,然后返回添加了打印功能的函数。调用
Decprator
函数使用@
语法,将其置于函数定义处,如下@log def now():print('2017-05-11')
调用结果:
>>> now() calls now(): 2017-05-11
其实,将
@log
放在now()
函数定义处就相当于执行了语句now=log(now)
8.偏函数
python的
functools
模块1提供了偏函数的支持,注意,这里说的偏函数不是数学意义上的偏函数。示例:使用
int()
函数实现由字符串对任意数制的转换int()
函数提供了这个功能,其接受一个额外的参数base
>>> int('12345',base=10) 12345 >>> int('12345',base=8) 5349
假如我们需要大量的把代码转换为2进制,这时我们希望有一个默认函数
def int2(s):return int(s,base=2)
>>> int2('1000001') 65
上面对
int2()
的定义,其实可以用python语法实现,也即:偏函数>>> import functools >>> int2=functools.partial(int,base=2) >>> int2('1000001') 65
这样就为我们省去了定义的麻烦。总结来说就是:当函数的参数太多,需要简化时,使用
fooltools.partial
可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
【Python专题】函数式编程相关推荐
- python采用函数式编程模式吗_Python函数与函数式编程
1 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创 ...
- 白话 Python 的函数式编程
今天和大家聊聊 Python 的函数式编程特性.所谓函数式编程,就是指代码中每一块都是不可变的(immutable),都是由 pure function 的形式组成.这里的 pure function ...
- Python的函数式编程--从入门到⎡放弃⎦
很早以前就听说过了函数式编程,印象中是一种很晦涩难懂的编程模式,但却一直没有去进行了解. 恰好这周组内的周会轮到我主持,一时也没想到要分享什么.灵光一闪,就选定函数式编程这个主题吧,反正组里的同事都没 ...
- 【Python】函数式编程
前言 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本 ...
- 用python处理excel数据做函数_如何使用python通过函数式编程完成excel中的数据处理及分析工作...
Excel是数据分析中最常用的工具,本篇文章通过python与excel的功能对比介绍如何使用python通过函数式编程完成excel中的数据处理及分析工作.在Python中pandas库用于数据处理 ...
- 函数式编程|python的函数式编程
面向过程,面向对象 面向过程: 分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了 面向对象: 把问题中的事务分解成各个对象,建立对象的目的不是为了完成一 ...
- 05 python 要点 (函数式编程)
复习时先看看这个:https://blog.csdn.net/weixin_39880623/article/details/110153616? 第一章 函数式编程 一.生成器 (generato ...
- python学习——函数式编程——高阶函数
python学习--函数式编程--高阶函数 函数式编程(高阶函数):1:map && reduce; 2 : filter; 3: sorted; ------------------ ...
- python的函数式编程玩法+年末小感
从小老师教编程语言就告诉分两种:面向过程和面向对象,正如同小学电脑课面对的是win95,仿佛世界上windows就是操作系统的别名,如今还是这样,高校的计算机中心都是windows,所以linux是要 ...
- python的函数式编程_Python函数式编程-概念理解,python
函数式编程-高级 一.函数的参数类型 1. 不可变类型参数 不可变类型参数有:整数,字典,字符串 传递不可变类型参数,不会影响参数本身. 代码: a = 100 print(f"函数外边a的 ...
最新文章
- 测试代码发布到博客效果(Windows Live Writer发布)
- C/C++、嵌入式秋招之SQL篇
- URL编码以及GET和POST提交乱码解决方案
- 201521123009 《Java程序设计》第12周学习总结
- 源代码主干分支开发四大模式
- ubantu 16.04 mysql_Ubuntu 16.04下安装MySQL
- SAP WebIDE Initialization process - 初始化逻辑分析
- webpack3 css,媒体查询不能使用CSS /样式加载器和Webpack3
- 【 Grey Hack 】万金油脚本:在路由器上获取shell
- html怎么关闭组合页面,html - 向HTML页面添加内部包装div [关闭] - 堆栈内存溢出
- Concepts in Games Development(游戏开发概述) 公开课笔记
- java 文件压缩_java实现文件压缩
- JS中的Map和Set实现映射对象
- 如何在Ubuntu 18.04上安装Elasticsearch Logstash Kibana(Elastic Stack)
- mysql点击计数器_高性能Mysql(第3版)_网站点击计数器
- 基于Spring Boot2 + Spring Security OAuth2 实现单点登陆(二)
- CMMI认证要求有哪些
- 高中英语单词名词分类
- 【软件定义汽车】【中间件】iceoryx冰羚
- 模糊测试工具Sulley开发指南(1)——安装Sulley(多图,超详细)
热门文章
- 数据库进阶·如何针对所有用户数据中没有的数据去加入随机的数据-蜻蜓Q系统用户没有头像如何加入头像数据-优雅草科技kir
- php读取目录中文文件名乱码解决方法
- Windows 安装程序进程错误代码和错误信息列表
- AngularJS之表格设置样式
- python定义字典长度_字典详解dict
- GO工具开发|基于网站API的子域名与IP反查工具(一)
- Psins之 test_SINS_GPS_153代码解析
- 2018美国大学计算机科学,2018usnews美国大学设计研究生计算机科学专业排名
- 中科蓝汛----自定义开关机时间
- php毕业设计 基于php+mysql旅游景区景点购票系统毕业设计开题报告功能参考