什么是高阶函数?把函数作为参数传入或把函数做为结果值返回,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。函数式编程的特点:

  • 函数本身可以赋值给变量,赋值后变量为函数;
  • 允许将函数本身作为参数传入另一个函数;
  • 允许返回一个函数。

在前面的章节中,我们知道可以用abs()这个函数来得到一个数的绝对值,如:

print('abs(-100):', abs(-100))

以上代码,输出:

abs(-100): 100

如果,我们把代码修改下,把abs赋值给一个变量:

f = abs
print(f(-100))

以上代码,输出:

100

可见,abs(-100)是函数调用,而abs是函数本身,要获得函数调用结果,我们可以把结果赋值给变量。函数本身也可以赋值给变量,即:变量可以指向函数,这时变量就获得了函数的功能,如上例中的 f ,直接调用f()和直接调用abs()完全相同。

那么函数名是什么呢?函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!

如果把abs指向其他对象,会有什么情况发生?

abs = 10
print(abs(-10))

把abs指向10后,就无法通过abs(-10)调用该函数了!因为abs这个变量已经不指向求绝对值函数而是指向一个整数10!当然实际代码绝对不能这么写,这里是为了说明函数名也是变量。

注:由于abs函数实际上是定义在import builtins模块中的,所以要让修改abs变量的指向在其它模块也生效,要用import builtins; builtins.abs = 10。关于什么是模块,后面会讲到,这里不要去纠结。

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

一个最简单的高阶函数:

def add(x, y, f):
return f(x) + f(y)

当我们调用add(-5, 6, abs)时,参数x,y和f分别接收-5,6和abs,根据函数定义,我们可以推导计算过程为:

x = -5
y = 6
f = abs
f(x) + f(y) ==> abs(-5) + abs(6) ==> 11
return 11

用代码验证下:

def add(x, y, f):
return f(x) + f(y) print(add(-5, 6, abs))

1、map函数

这是Python内置的一个函数,map()函数接收两个参数,一个是函数,一个是Iterable(迭代器对象),map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator(迭代器)返回:

def f(x):
"""
返回一个数的3次方
:param x: 数
:return: 3次方后的结果
"""
return x**3 r = map(f, [1, 2, 3, 4, 5]) print(list(r))

以上代码,输出:

[1, 8, 27, 64, 125]

map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

当然,不需要map()函数,写一个循环,也可以计算出结果:

def f(x):
"""
返回一个数的3次方
:param x: 数
:return: 3次方后的结果
"""
return x**3 L = []
for n in [1, 2, 3, 4, 5]:
L.append(f(n)) print(L)

执行后,结果是一样的,但这样的写法,我们并不能直观的知道f()是作用在列表的所有元素上,并返回一个列表,我们必须读了源代码后才知道。

所以,map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x3,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:

print(list(map(str, [1, 2, 3, 4, 5])))

以上代码,输出:

['', '', '', '', '']

当然,更多的时候我们也会配合lambda来使用,如:

r = map(lambda x: x**3, [1, 2, 3, 4, 5])

print(list(r))

以上代码,输出:

[1, 8, 27, 64, 125]

2、reduce函数

reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

对一个序列求和,就可以用reduce实现:

from functools import reduce

def add(x, y):
return x + y print('reduce(add, [1, 3, 5, 7, 9]) = ', reduce(add, [1, 3, 5, 7, 9]))

以上代码,输出:

reduce(add, [1, 3, 5, 7, 9]) =  25

当然求和运算可以直接用Python内建函数sum(),思考:如何把序列 [1, 2, 3, 4, 5] 转化为整型的 12345 ,下面给出代码但请尽可能自己先写出

from functools import reduce

def f(x, y):
return x*10 + y res = reduce(f, [1, 2, 3, 4, 5]) print(res)

思考:假如python没有提供 int() 函数,如何使用 map与reduce自己写一个函数,实现将 '123456' 转化为 ,下面给出代码但请尽可能自己先写出:

from functools import reduce

def str2int(s):
"""
将字符串转为数字
:param s: 要转化的字符串
:return: 数字
""" DIGITS = {'': 0, '': 1, '': 2, '': 3, '': 4, '': 5, '': 6, '': 7, '': 8, '': 9}
def char2num(c):
"""
字符转数字
:param c:字符
:return: 数字
"""
return DIGITS[c] def f(x, y):
return x*10 + y resList = map(char2num, s) # 将字符串转为列表 return reduce(f, resList) # 将列表元素依次排列组成数字,并返回 print(str2int(''))

3、filter函数

Python内建的filter()函数用于过滤序列。filter()接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

def is_odd(n):
return n % 2 == 1 res = list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8]))
print(res)

以上代码,输出:

[1, 3, 5, 7]

注:filter()函数返回的是一个Iterator,也就是一个惰性序列,filter()的作用是从一个序列中筛出符合条件的元素。由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。

4、sorted函数

排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

Python内置的sorted()函数就可以对list进行排序:

print(sorted([36, 5, -12, 9, -21]))

以上代码,输出:

[-21, -12, 5, 9, 36]

它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

print(sorted([36, 5, -12, 9, -21], key=abs))

以上代码,输出:

[5, 9, -12, -21, 36]

key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。

这个是数字,那字符串排序是怎么样的呢?我们来看实例:

print(sorted(['hello', 'world', 'roy', 'python', 'c++']))

以上代码,输出:

['c++', 'hello', 'python', 'roy', 'world']

默认情况下,对字符串排序,是按照ASCII的大小比较的,每个字符依次比较(两个字符串比较,先比较第一个字符,当第一个字符分出大小时则结束比较且比较的结果即为第一个字符相比较的结果,当第一个字符相同时则比较第二个字符,第二个字符相同时则比较第三个,依次下去直到得出结果),由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。

可以用 reverse=True 进行反向排序:

print(sorted([36, 5, -12, 9, -21], reverse=True))
print(sorted(['hello', 'world', 'roy', 'python', 'c++'], reverse=True))

以上代码,输出:

[36, 9, 5, -12, -21]
['world', 'roy', 'python', 'hello', 'c++']

python3 第二十章 - 函数式编程之Higher-order function(高阶函数)的更多相关文章

  1. python3 第二十二章 - 函数式编程之Decorator(装饰器)

    前面我们说了,在python中,一切皆对象.函数也是一个对象,而且函数对象可以被赋值给变量,通过变量也能调用该函数.如: def sayHello(name): print(name + ' hell ...

  2. Python函数式编程之map()

    Python函数式编程之map() Python中map().filter().reduce()这三个都是应用于序列的内置函数. 格式: map(func, seq1[, seq2,…]) 第一个参数 ...

  3. 函数式编程之 Python

    上接 python 函数式编程学习笔记 参考:www.sigai.cn/ 1 函数式编程概述 前提:函数在 Python 中是⼀等对象 工具:built-in ⾼阶函数:lambda 函数:opera ...

  4. Ramda函数式编程之PHP

    0x00 何为函数式编程 网上已经有好多详细的接受了,我认为比较重要的有: 函数是"第一等公民",即函数和其它数据类型一样处于平等地位 使用"表达式"(指一个单 ...

  5. java函数式编程之lambda表达式

    作为比较老牌的面向对象的编程语言java,在对函数式编程的支持上一直不温不火. 认为面向对象式编程就应该纯粹的面向对象,于是经常看到这样的写法:如果你想写一个方法,那么就必须把它放到一个类里面,然后n ...

  6. Python3基础(3)集合、文件操作、字符转编码、函数、全局/局部变量、递归、函数式编程、高阶函数

    ---------------个人学习笔记--------------- ----------------本文作者吴疆-------------- ------点击此处链接至博客园原文------ 1 ...

  7. [Python3] 035 函数式编程 高阶函数

    目录 函数式编程 之 高阶函数 1. 引子 2. 系统提供的高阶函数 3. functools 包提供的 reduce 4. 排序 函数式编程 之 高阶函数 把函数作为参数使用的函数,叫高阶函数 1. ...

  8. Python3学习之路~3.2 递归、函数式编程、高阶函数、匿名函数、嵌套函数

    1 递归 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. def calc(n): print(n) if int(n / 2) == 0: return n r ...

  9. 高阶函数 - Higher Order Function

    一个函数如果有 参数是函数 或 返回值是函数,就称为高阶函数. 这篇文章介绍高阶函数的一个子集:输入 fn,输出 fn'. 按 fn 与 fn' 功能是否一致,即相同输入是否始终对应相同输出,把这类高 ...

随机推荐

  1. ul li内的文字水平居中显示

    head><style rel="stylesheet" type="text/css" >#top{height:140px;}#top u ...

  2. 使用Q进行同步的Promises操作

    如何通过使用Q来并发执行多个promises呢? Q(Q(1), Q(2), Q(3)) .then(function (one, two, three) { console.log(one); co ...

  3. [Spark内核] 第32课:Spark Worker原理和源码剖析解密:Worker工作流程图、Worker启动Driver源码解密、Worker启动Executor源码解密等

    本課主題 Spark Worker 原理 Worker 启动 Driver 源码鉴赏 Worker 启动 Executor 源码鉴赏 Worker 与 Master 的交互关系 [引言部份:你希望读者 ...

  4. Java学习笔记7(简易的超市库存管理系统示例)

    用以前学过的知识,可以简单地做一个超市库存管理系统: 定义一个商品类: public class FruitItem { int ID; String name; double price; int ...

  5. linux 卸载安装node npm

    1. 卸载node npm (1) 先卸载 npm: sudo npm uninstall npm -g (2) 然后卸载 Node.js. (2.1) 如果是 Ubuntu 系统并使用 apt-ge ...

  6. mysql5.7 设置远程访问

    mysql5.7设置远程访问不是和网上说的一样建个用户赋个权限就可以访问的.比如下边这个就是建用户赋权限,可能在之前的版本可以,但是我在我的mysql上一直不行.为此烦了好久!!!项目都耽误了!! 一 ...

  7. Linux audio驱动模型

    linux驱动 alsa模型: Linux ALSA声卡驱动之一:ALSA架构简介 Linux ALSA声卡驱动之二:声卡的创建 Linux ALSA声卡驱动之三:PCM设备的创建 Linux ALS ...

  8. WCF(一):初识WCF

    目录: 一.什么是WCF 二.WCF能做什么 三.WCF的模型 四.WCF的基本概念 五.WCF的快速创建 1.WCF是什么 A.WindowsCommunication Foundation(WCF ...

  9. python网络数据采集(伴奏曲)

    这里是前章,我们做一下预备.之前太多事情没能写博客~..             (此博客只适合python3x,python2x请自行更改代码) 首先你要有bs4模块 windows下安装:pip3 ...

  10. BZOJ 3038: 上帝造题的七分钟2【线段树区间开方问题】

    3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1469  Solved: 631[Submit][Status][Dis ...