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

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

在前面的章节中,我们知道可以用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. angular4.0路由传递参数、获取参数最nice的写法

    研究ng4的官网,终于找到了我想要的方法.我想要的结果是用'&'拼接参数传送,这样阅读上是最好的.否则很多'/'的拼接,容易混淆参数和组件名称.一般我们页面跳转传递参数都是这样的格式:http ...

  2. shell脚本的if语句,判断某程序是否存在,不存在启动该程序!

    想必大家都知道 "如果......那么......" 这种语法的应用吧! 当然呢,linux下对于这种用法也是有所考虑的,很多时候我们都需要写一个shell脚本,难免会避免if语句 ...

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

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

  4. IRP的同步

    应用层对设备的同步与异步操作 以WriteFile为例,一般的同步操作是调用WriteFile完成后,并不会返回,应用程序会在此处暂停,一直等到函数将数据写入文件中并正常返回,而异步操作则是调用Wri ...

  5. H5 调用本地相机并压缩上传(是从angular的ionic项目中截取的)

    html部分 <div class="list_upload item bg_white"> <div class="itemImg pic_uploa ...

  6. 数据结构之链表-链表实现及常用操作(C++篇)

    数据结构之链表-链表实现及常用操作(C++篇) 0.摘要 定义 插入节点(单向链表) 删除节点(单向链表) 反向遍历链表 找出中间节点 找出倒数第k个节点 翻转链表 判断两个链表是否相交,并返回相交点 ...

  7. js面向对象学习笔记(三):原型

    //原型:改写对象下面公用的方法或者属性,让公用的方法或者属性在内存中只存在一份(提高性能)//原型:prototype :要写在构造函数的下面var arr =[1,2,3,4,5];var arr ...

  8. 初识maven及其安装步骤!!

    maven(01)--安装及其介绍   1:下载maven windows下载 2:将下载文件夹解压,然后放在一个安装目录(可任意选择),例如就放在D盘的根目录 然后在设置环境变量,新建一个环境变量, ...

  9. 如何让低版本IE浏览器支持HTML5标签并为其设置样式

    现代的浏览器都支持HTML5,HTML5定义了 8 个新的 HTML 语义元素.所有这些元素都是 块级 元素. 为了能让旧版本的浏览器正确显示这些元素,你可以设置 CSS 的 display 属性值为 ...

  10. Dig out WeChat deleted chat messages on Android Phone

    As we know that WeChat will wipe deleted chat messages. That's why forensic guys could  not dig out ...