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的__builtin__模块中的一些要点知识
May 02 Python
使用FastCGI部署Python的Django应用的教程
Jul 22 Python
Python语言的变量认识及操作方法
Feb 11 Python
Python嵌套列表转一维的方法(压平嵌套列表)
Jul 03 Python
Django实现学员管理系统
Feb 26 Python
Python OpenCV实现视频分帧
Jun 01 Python
PyQt5创建一个新窗口的实例
Jun 20 Python
python+selenium select下拉选择框定位处理方法
Aug 24 Python
python函数声明和调用定义及原理详解
Dec 02 Python
基于python3的socket聊天编程
Feb 17 Python
Python爬虫新手入门之初学lxml库
Dec 20 Python
ROS系统将python包编译为可执行文件的简单步骤
Jul 25 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
php横向重复区域显示二法
2008/09/25 PHP
php ajax 静态分页过程形式
2011/09/02 PHP
BOOM vs RR BO5 第四场 2.14
2021/03/10 DOTA
一些主流JS框架中DOMReady事件的实现小结
2011/02/12 Javascript
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
2012/07/31 Javascript
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
2012/08/14 Javascript
打开新窗口关闭当前页面不弹出关闭提示js代码
2013/03/18 Javascript
让网页跳转到指定位置的jquery代码非书签
2013/09/06 Javascript
文本框(input)获取焦点(onfocus)时样式改变的示例代码
2014/01/10 Javascript
jQuery制作的别致导航有阴影背景高亮模式窗口
2014/04/15 Javascript
JQuery中serialize()、serializeArray()和param()方法示例介绍
2014/07/31 Javascript
Javascript控制input输入时间格式的方法
2015/01/28 Javascript
asp.net+js实现金额格式化
2015/02/27 Javascript
JavaScript代码实现禁止右键、禁选择、禁粘贴、禁shift、禁ctrl、禁alt
2015/11/17 Javascript
angular2倒计时组件使用详解
2017/01/12 Javascript
js构造函数创建对象是否加new问题
2018/01/22 Javascript
Vue-Router2.X多种路由实现方式总结
2018/02/09 Javascript
vue搜索和vue模糊搜索代码实例
2019/05/07 Javascript
微信小程序文章列表功能完整实例
2020/06/03 Javascript
JS变量提升及函数提升实例解析
2020/09/03 Javascript
[00:33]2018DOTA2亚洲邀请赛TNC出场
2018/04/04 DOTA
python3使用urllib示例取googletranslate(谷歌翻译)
2014/01/23 Python
python中根据字符串调用函数的实现方法
2016/06/12 Python
Python实现的多线程http压力测试代码
2017/02/08 Python
python操作oracle的完整教程分享
2018/01/30 Python
Python小进度条显示代码
2019/03/05 Python
Python魔法方法功能与用法简介
2019/04/04 Python
Python分支语句与循环语句应用实例分析
2019/05/07 Python
python程序 创建多线程过程详解
2019/09/23 Python
基于Python实现大文件分割和命名脚本过程解析
2019/09/29 Python
Keras 实现加载预训练模型并冻结网络的层
2020/06/15 Python
Dr. Martens马汀博士德国官网:马丁靴鼻祖
2019/12/26 全球购物
美术毕业生求职信
2014/02/25 职场文书
优秀教育工作者事迹材料
2014/12/24 职场文书
高一地理教学工作总结
2015/08/12 职场文书
HTML5+CSS+JavaScript实现捉虫小游戏设计和实现
2021/10/16 HTML / CSS