Python函数式编程实例详解


Posted in Python onJanuary 17, 2020

本文实例讲述了Python函数式编程。分享给大家供大家参考,具体如下:

函数式编程就是一种抽象程度很高的编程范式,从计算机硬件->汇编语言->C语言->Python抽象程度越高、越贴近于计算,但执行效率也越低。纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

Python对函数式编程提供部分支持,支持高阶函数(函数可以作为变量传入),支持闭包(返回一个函数),有限地支持匿名函数。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

1、高阶函数

即可以通过变量名指向函数,函数通过变量名作为参数传给另一个函数,并通过变量名来使用。例如下面将开方函数math.sqrt作为参数传递给变量f,变量名f就指向了函数math.sqrt,再通过变量f使用该函数给x、y开方。

import math
def add(x, y, f):
  return f(x) + f(y) # 函数作为参数传递给f来调用
res = add(25, 9, math.sqrt)
print(res)

map函数接收一个函数 f 和一个 list,并把函数 f 依次作用在 list 的每个元素上,得到一个iterators并返回。

def format_name(s):
  return s[0].upper()+s[1:].lower()  #将列表的每个元素首字母大写,其他小写
print(list(map(format_name, ['adam', 'LISA', 'barT'])))
#输出:['Adam', 'Lisa', 'Bart']

filter()根据判断函数f的结果自动过滤掉不符合条件的元素,以iterators返回剩下的元素

def is_odd(x):
  return x % 2 == 1 # 过滤函数,x为奇返回True
f_res = filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
print(list(f_res))  # 输出过滤后的结果list:1 7 9 17

sorted()函数用于对可迭代的对象进行排序,参数key=指定排序的关键字,这里可以借助functools.cmp_to_keys()将比较方法映射为自定义的方法。例如实现了降序排列,比较函数cmp返回值 -1 代表a 应该排在 b 的前面,如果a排在b 的后面返回 1。如果 a、b相等返回 0。

import functools
def cmp(a, b):
  if b < a:
    return -1
  if a < b:
    return 1
  return 0
a = [1, 2, 5, 4]
print(sorted(a, key=functools.cmp_to_key(cmp)))

2、匿名函数和闭包

有时函数简单到只有一个表达式时,为了简化代码可以使用匿名函数来代替,匿名函数一般形式为lambda 参数:返回表达式,例如lambda x:x*x,就是传入x参数并返回x的平方。例如在使用map()函数时需要传入一个函数用于list的元素,此时可以使用匿名函数作为参数

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
res = map(lambda x: x * x, lst)  # 将匿名函数作用于lst
print(list(res))

函数的闭包(Closure)是指内层函数引用了外层函数的变量,然后将内层函数像变量一样返回的情况。例如函数calc_prod()接收一个list,在其内部定义一个函数multiply,计算list元素的乘积并将multiply返回。用f接收calc_prod()的返回函数,并在之后调用该函数

def calc_prod(lst):
  def multiply():
    res=1
    for i in lst:
      res=res*i
    return res
  return multiply  # 将函数返回
f = calc_prod([1, 2, 3, 4])  # 接收返回函数
print(f())  # 调用返回函数

注意在函数闭包时要确保引用的局部变量在函数返回后不能变。例如下面的例子,当count()函数返回3个函数时,由于f1、f2、f3并没有被调用,所以并未计算 i*i。当 f1 被调用时,这3个函数所引用的变量 i 的值已经变成了3,所以此时使用的变量i的值已经发生了改变,三个函数的输出都是9。

def count():
  fs = []
  for i in range(1, 4):
    def f():
      print(i)  # 函数f1()调用时i已经变为3
      return i*i
    fs.append(f)
  return fs
f1, f2, f3 = count()
print(f1())      # 输出9而不是1

3、函数装饰器

函数装饰器是指在原有函数的基础上对函数作修改和装饰操作。其基本思想是,既然函数可以像变量一样作为参数传入并且返回,那么我们可以将原来的函数传入装饰器函数,然后增加我们需要的操作,之后在将原函数返回出来。

例如下面定义了一个装饰器log用于打印函数名称,原函数作为参数f传入。在装饰器中定义新的函数fn,其中参数列*args和**kw代表自适应参数个数,防止不同参数个数的函数在使用装饰器时不匹配。在新函数fn中输出原函数的名称,之后将原函数原封不动地调用一遍并返回出去。最后返回新函数。

在使用装饰器时,只需要在函数的定义前加一行@装饰器名

def log(f): # 定义装饰器log
  def fn(*args, **kw): # 定义新函数
    print('函数名: ' + f.__name__)  # 打印函数名
    return f(*args, **kw) # 在新函数中调用原函数并返回结果
  return fn # 返回新函数
@log # 为函数add添加装饰器
def add(x, y):
  return x + y
print(add(1, 2))

如果希望给装饰器传入一个参数,则需要定义三重嵌套的函数,在最外层增加一层函数用于接收参数。例如希望在打印函数名之前输出传入的参数“DEBUG”

def log(prefix):
  def log_decorator(f):
    def wrapper(*args, **kw):
      print '[%s] %s()...' % (prefix, f.__name__)
      return f(*args, **kw)
    return wrapper
  return log_decorator
@log('DEBUG')  # 为装饰器传入参数
def test():
  pass
test()

由于装饰器实际上是创建了新的函数fn并替代了原函数,所以原函数的相关信息例如函数名会被覆盖,可以用@functools.wraps(f)来复制原函数的信息以保留下来。

import functools
def log(f):
  @functools.wraps(f)
  def fn(*args, **kw):
    print 'call...'
    return f(*args, **kw)
  return fn

偏函数可以为函数填上一个固定的参数值,从而生成一个新的函数。例如原函数add需要两个参数x、y,通过指定y=1得到偏函数add1,这个函数只需要输入一个参数x,从而计算x+1的值。

import functools
def add(x, y):
  return x + y
add1 = functools.partial(add, y=1)
print(add2(3))  # 输出结果为4

关于Python相关内容感兴趣的读者可查看本站专题:《Python函数使用技巧总结》、《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
零基础写python爬虫之urllib2使用指南
Nov 05 Python
Python脚本暴力破解栅栏密码
Oct 19 Python
python开发之thread线程基础实例入门
Nov 11 Python
Python多层嵌套list的递归处理方法(推荐)
Jun 08 Python
linux环境下python中MySQLdb模块的安装方法
Jun 16 Python
Python基于回溯法子集树模板解决野人与传教士问题示例
Sep 11 Python
Python实现的多进程和多线程功能示例
May 29 Python
Python中作用域的深入讲解
Dec 10 Python
使用Django和Postgres进行全文搜索的实例代码
Feb 13 Python
Python实现屏幕录制功能的代码
Mar 02 Python
Python reversed函数及使用方法解析
Mar 17 Python
python+appium+yaml移动端自动化测试框架实现详解
Nov 24 Python
python实现tail -f 功能
Jan 17 #Python
解决Python命令行下退格,删除,方向键乱码(亲测有效)
Jan 16 #Python
python对象销毁实例(垃圾回收)
Jan 16 #Python
python读取dicom图像示例(SimpleITK和dicom包实现)
Jan 16 #Python
.dcm格式文件软件读取及python处理详解
Jan 16 #Python
用python解压分析jar包实例
Jan 16 #Python
Python3 实现爬取网站下所有URL方式
Jan 16 #Python
You might like
2020年4月放送!《Princess Connect Re:Dive》制作组 & 角色声优公开!
2020/03/06 日漫
WAR3重制版DOTA 5V5初体验
2020/04/09 DOTA
php面向对象全攻略 (二) 实例化对象 使用对象成员
2009/09/30 PHP
写出高质量的PHP程序
2012/02/04 PHP
PHP微信开发之根据用户回复关键词\位置返回附近信息
2016/06/24 PHP
php头像上传预览实例代码
2017/05/02 PHP
php 多进程编程父进程的阻塞与非阻塞实例分析
2020/02/22 PHP
jQuery下的动画处理总结
2013/10/10 Javascript
javascript控制在光标位置插入文字适合表情的插入
2014/06/09 Javascript
基于BootStrap Metronic开发框架经验小结【七】数据的导入、导出及附件的查看处理
2016/05/12 Javascript
jquery.validate使用详解
2016/06/02 Javascript
jQuery条件分页 代替离线查询(附代码)
2017/08/17 jQuery
解决angularjs中同步执行http请求的方法
2018/08/13 Javascript
解决vuejs 使用value in list 循环遍历数组出现警告的问题
2018/09/26 Javascript
vue 属性拦截实现双向绑定的实例代码
2018/10/24 Javascript
微信小程序非swiper组件实现的自定义伪3D轮播图效果示例
2018/12/11 Javascript
JS实现可视化音频效果的实例代码
2020/01/16 Javascript
基于javascript处理二进制图片流过程详解
2020/06/08 Javascript
React冒泡和阻止冒泡的应用详解
2020/08/18 Javascript
[03:14]2014DOTA2西雅图国际邀请赛 EG战队巡礼
2014/07/07 DOTA
Tensorflow的可视化工具Tensorboard的初步使用详解
2018/02/11 Python
python数据处理 根据颜色对图片进行分类的方法
2018/12/08 Python
用Python解决x的n次方问题
2019/02/08 Python
Python3解释器知识点总结
2019/02/19 Python
Python命名空间及作用域原理实例解析
2020/08/12 Python
事业单位辞职信范文
2014/01/19 职场文书
中药学专业求职信
2014/05/31 职场文书
银行柜员与客户起冲突检讨书
2014/09/27 职场文书
道德模范事迹材料
2014/12/20 职场文书
汇报材料怎么写
2014/12/30 职场文书
如何在Python中创建二叉树
2021/03/30 Python
python制作图形界面的2048游戏, 基于tkinter
2021/04/06 Python
详细总结Python常见的安全问题
2021/05/21 Python
python中%格式表达式实例用法
2021/06/18 Python
nginx的zabbix 5.0安装部署的方法步骤
2021/07/16 Servers
Python利用Turtle绘制哆啦A梦和小猪佩奇
2022/04/04 Python