53、Python之函数高级:一等公民中的高阶函数,高在哪里?

引言

虽然在Python中函数也是对象,是一等公民,有出现在四个地方的特权,详情可以查看上一篇文章。但是,即便已经是“一等公民”了,Python中的函数,还是有普通函数和高阶函数的区分的。

今天这篇文章就来简单聊一下高阶函数,主要内容大概有:

1、什么是高阶函数

2、高阶函数的适用场景

3、几个内置的高阶函数

4、大数据处理中的入门案例wordcount

什么是高阶函数

在编程语言的语境中,所谓的“高阶函数(Higher-Order Function)”,是指在编程中至少满足以下两个条件之一的函数:

1、接受一个或者多个函数作为参数:高阶函数的内部可以调用传入的函数,从而实现更高级别的抽象和代码服复用。

2、返回一个函数:高阶函数可以生成新的函数,从而实现动态行为和延迟计算的特性。

从以上的描述可以看出,虽然函数作为一等公民符合四个特权。但是,特权可以用,也可以不用。如果用了函数作为参数,或者函数作为返回值的特权,那么该函数才是高阶函数。

高阶函数的适用场景

知道了什么是高阶函数,但是,到底有什么用呢?这就要涉及到高阶函数的适用场景了。

由于高阶函数要么是参数接收函数对象,要么是返回值是函数对象,所以,基于这么两种场景,高阶函数可以有以下几个相对来说比较典型的应用:

1、事件处理与回调函数

函数作为参数传递,可以有效支撑支撑GUI编程中的事件处理机制,以及相应的事件回调的功能。

2、数据处理和转换

很多时候对数据的处理,需要分多个处理环节,比如数据筛选、数据的映射转换、数据的汇聚等。这些通用的数据处理环节可以定义为高阶函数,而具体的处理逻辑的函数作为高阶函数的参数进行传递。

3、闭包与装饰器

高阶函数可以返回一个函数对象的特性,使得可以通过高阶函数对普通函数进行装饰、增强,从而实现更多的动态行为。

几个内置的“高阶函数”

接下来看几个Python中比较实用的高阶函数。

需要说明的是,虽然很多教材或者文章里,尝尝把filter、map、reduce、sorted等一起描述为Python中常用的高阶函数。但是,实际上这是一个“美丽”的错误。

map内置类

看下map的定义:

9f18a6d7b355442808695fd67bed016d.jpeg

可以看出,map不是一个高阶函数,而是一个Python内置类,这个内置类的初始化函数__init__()接收一个函数参数,以及一个或者多个可迭代对象。

map对象是一个可迭代对象,可迭代对象的元素是对参数中的可迭代对象元素进行计算得来的。

虽然,哪怕把map当作函数来使用,似乎也没有什么问题,但是,建议还是不要人云亦云,显得孤陋而寡闻。

filter内置类

同map一样,filter其实也是一个内置类,而非所谓的高阶函数。同样看一下filter的定义:

a4c064d082a7fb0f3832598241037ffe.jpeg

filter内置类的初始化函数__init__()跟map的有些不同,函数参数可以为None,可迭代对象只有一个。

reduce()高阶函数

这里终于出现了高阶函数,reduce函数在functools模块中,需要手动导入一下。定义如下:

89ed983d82372dad77a9c68630135c7d.jpeg

可以看到,reduce()函数是真正的高阶函数,函数接收3个参数:

1、function:传入一个函数对象,这个函数对象必须接收两个参数,返回一个值。

2、sequence:序列对象,reduce函数通过调用function对象对该迭代器进行归约操作。

3、initial:带默认值参数,表示归约操作的初始值,从定义看,这个默认值就是一个object(),应用了单例模式,前面已经介绍过,基于模块导入的单例模式实现。

reduce()函数的运算过程:

1、基于传入的序列对象,构造一个迭代器。

2、判断initial参数是否传参,如果仍然是单例对象,则表示没有初始值。没有初始值,则从迭代器中取出第一个元素作为function参数的第一个参数;否则,将初始值作为function参数的第一个参数。

3、遍历迭代器,取出的元素作为函数function的第二个参数,调用function之后,返回值作为function的第一个参数进行下一轮迭代,知道遍历结束,返回最终的function函数的返回值。

sorted高阶函数

sorted()也是一个真正的高阶函数,这个函数在之前也介绍过,就不再展开了,只把函数的定义贴在这里:

cf783e246d89bdbf62aaa81576415c91.jpeg

大数据处理中的入门案例wordcount

之所以介绍高阶函数,是因为在后续要介绍的闭包、装饰器等,本质上都是高阶函数。这里暂时介绍到这里,后续再逐步展开。

接下来,通过组合使用下filter、map、reduce等,来试着模拟一下大数据处理中的经典入门案例:word count。

需要说明的是,以下仅是模拟,需要假想是海量的数据,单台服务器没法进行处理,需要进行分布式多节点的计算,迭代多次,最终汇总得出最终结果的场景。

所以,小数据量的单词计数的编码,也许很简单。但是,在大数据场景下,计算范式会有些不同,如果没有接触过大数据处理的,可能会觉得有些别扭。

直接上代码:

from functools import reduce
from collections import defaultdict

# 莎士比亚的几句经典
sentences = """To be or not to be: that is the question
Good night good night Parting is such sweet sorrow
Fair is foul and foul is fair
Tomorrow and tomorrow and tomorrow creeps in this petty pace from day to day
If music be the food of love play on
Better a witty fool than a foolish wit
All the world's a stage and all the men and women merely players
The fool doth think he is wise but the wise man knows himself to be a fool
"""


def reduce_by(data):
    res = defaultdict(list)
    for word, cnt in data:
        res[word].append(cnt)
    return res


# 1、切分为单词,从而模拟后续分布式的单词计数
words = sentences.replace('\n', ' ').split(' ')
print(words)
# 2、适用filter和map内置类,进行数据的过滤(为空的单词剔除掉),并对数据格式进行转换:word -> (word, 1)
word_and_one = map(lambda x: (x, 1), filter(lambda x: x != '', words))
# 3、对数据进行排序,模拟shuffle、分发的操作
sorted_data = sorted(word_and_one, key=lambda x: x[0])
print(sorted_data)
# 4、模拟,将所有相同的单词进行汇聚 [(word, 1), (word, 1)] -> [(word, [1, 1])]
reduce_by_data = reduce_by(sorted_data)
print(reduce_by_data)
# 5、计算最终结果:{word: 10}
result = {word: reduce(lambda x, y: x + y, cnt) for word, cnt in reduce_by_data.items()}
print(result)

执行结果:

1cdbb92c5b8d9b0ce8ae007263de39b3.jpeg

相关的核心代码,都已经写了注释,感兴趣的同学,可以自行查阅。

总结

本文简单介绍了Python中高阶函数的概念,并理清了map/filter这两个是内置类而非高阶函数的概念,最后,模拟了大数据分布式计算的典型的入门案例word count。

感谢您的拨冗阅读,希望对您学习Python有些许帮助。

c774e6988a32c579f73a5e28d880bf0a.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫理的日知录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值