社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

白话 Python 的函数式编程

MacTalk • 7 年前 • 783 次点击  

今天和大家聊聊 Python 的函数式编程特性。所谓函数式编程,就是指代码中每一块都是不可变的(immutable),都是由 pure function 的形式组成。这里的 pure function 是指函数本身相互独立,互不影响,对于相同的输入,总会有相同的输出。也就是我们常说的没有副作用。举个很简单的例子,比如,对于一个列表,我想让列表中的元素值都变为原来的两倍,我们可以写成下面的形式:

def multiply_2(l): for index in range(0, len(l)): l[index] *= 2 return l

这就不是一个 pure function,因为列表中元素的值被改变了,如果我调用 multiply_2() 这个函数多次,那么每次得到的结果都不一样。要想让其成为一个pure function,就得写成下面的形式,重新创建一个新的列表并返回。

def multiply_2_pure(l): new_list = []  for item in l: new_list.append(item * 2)  return new_list

函数式编程的优点主要在于其 pure function 和不可变的特性使得程序更加健壮,易于 debug 和测试,缺点主要在于限制多,难写。当然 Python 不同于其他一些语言,比如 Scala,他并不是一门纯粹的函数式编程语言,但是 Python 也提供了一些函数式编程的特性,值得我们了解和学习。

Python 主要提供了这么几个函数 Map, Filter 和 Reduce,通常结合匿名函数 lambda 一起使用,我逐一介绍一下:

对于 Map(function, iterable) 函数,前面的例子提过,他表示对 iterable 中的每个元素运用 function 这个函数,最后返回一个新的可遍历的集合,比如上面对列表中每个元素乘2用map可以表示为

l = [1, 2, 3, 4, 5]new_list = map(lambda x: x * 2, l) # [2, 4, 6, 8, 10]

我们再来看一下 Python 提供的函数式编程的接口的性能,就以 Map 为例,上述的例子还可以用 for 循环和 list comprehension 实现,我们来比较一下他们的速度:

python3 -mtimeit -s’xs=range(1000000)' 'map(lambda x: x*2, xs)'输出结果:2000000 loops, best of 5: 171 nsec per looppython3 -mtimeit -s’xs=range(1000000)' '[x * 2 for x in xs]'输出结果:5 loops, best of 5: 62.9 msec per looppython3 -mtimeit -s’xs=range(1000000)’ 'l = []' 'for i in xs: l.append(i * 2)'输出结果:5 loops, best of 5: 92.7 msec per loop

可以看到 map 是最快的,因为 map 函数是直接由 C 语言写的,运行时不需要通过 Python 解释器间接调用,因此运行速度最快。

对于 Filter(function, iterable) 函数,和 map 函数类似,function 同样表示一个函数对象,表示对 iterable 中的每个元素使用 function 判断,返回 True 或者 False,最后将返回 True 的元素组成一个新的可遍历的集合,比如我要返回一个列表中的所有偶数,可以写成

l = [1, 2, 3, 4, 5]new_list = filter(lambda x: x % 2 == 0, l) # [2, 4]

对于 Reduce(function, iterable) 函数,通常用于对一个集合做一些累积操作。function 同样是一个函数对象,规定他有两个参数,表示对 iterable 中的每个元素以及上一次调用后的结果运用 function 进行计算,因此最后返回的是一个单独的数值,比如,我想要计算列表元素的乘积,可以表示为:

l = [1, 2, 3, 4, 5]product = reduce(lambda x, y: x * y, l) # 1*2*3*4*5 = 120

类似的,Filter,Reduce 的功能也可以用 for 循环或者 list comprehension 来实现,但是速度都不如 Filter 或者 Reduce。

通常来说,如果你想对一个集合中的元素进行一些操作,如果是一些非常简单的操作,比如相加,累积,那么我们优先考虑 Map、Filter、Reduce 或者 list comprehension 的形式。

在这两者之中,如果数据量非常大,比如机器学习的应用,那我们一般更倾向于函数式编程的表示,因为效率更高,如果数据量不多,并且你想要自己的程序更加 Pythonic(Python 化),那么运用 list comprehension 的情况也是很常见的。如果你要对集合中的元素做一些比较复杂的操作,考虑到代码的可读性,这时我们通常会使用 for 循环,因为更加清晰明了。


以上内容来自极客时间新上线的专栏「Python 核心技术与实战」的备稿内容中的一小节,完整文章还包括了匿名函数 lambda 的详解,还未发布,先睹为快。今天是 Python 专栏优惠期最后一天,已经有 8000+ 用户加入学习,也推荐给你,大数据时代,Python 必学必会。

另外,有些基础稍弱的同学希望我再开一个「零基础学 Python」视频课的大团,我说不用,今天给大家做了个新功能,口令码。目前零基础学 Python 课正在 129 拼团中,参与拼团时选中优惠口令,输入口令码「MACE3K2YW」,立减 30 元,99 元订阅。目前零基础学 Python 的 71 讲视频课已经全部更新完毕,学习人数超过了 12500 人。

口令码憋告诉别人,也别弄错课程哦。扫码进入口令通道

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/33451