Python函数式编程
函数式编程是近些年来大家愈发重视的一种编程范式,python和ruby等语言中也有了各种函数式语言的特性,如lambda演算等,因此掌握函数式编程尤为重要。笔者将通过对内建函数map和reduce的实现来简单讲述函数式编程的一些概念。
- map函数:
map(func,seq1[,seq2…])
map函数将func作用于seq中的每一个元素并用一个列表给出返回值。
下面是我自己的map实现:
def MyMap(f,seq):
def iter(n,l):
if(n < 0):
l.reverse()
return l
else:
l.append(f(seq[n]))
return iter(n-1,l)
return iter(len(seq)-1,[])
r = MyMap(lambda x:x+1,[1,2,3,4,5,6,7,8,9])
print(r)
在这个函数里,我定义了另一个函数iter,这样在任意位置定义函数的写法也是函数式语言的特性之一,因为函数是“一等公民”。
这里的iter用了尾递归的写法,之所以这么写是为了让函数更加“函数式”,因为函数式语言中没有循环语句。
不过因为python的特性,如l.reverse()这样的语句是没有返回值的,所以无法写入return中,只能用命令式的方法表达。
我们的目的是让MyMap返回一个list,而这个list又由iter来编辑,所以就让iter在结束的时候返回list,并且把iter写在MyMap返回值中,从而传递list。
在倒数第二行,我用了一个lambda函数(匿名函数),这个函数的意义在于方便定义那种只用一次的函数,不用专门为它取名字,这一特性让程序更加简洁干净。
- reduce函数
reduce(func,seq[,init])
reduce函数即化简,它每次迭代,将上一次的迭代结果与下一个元素一同执行一个二元的func函数。
自己的实现如下:
def MyReduce(f,seq):
def iter(n):
if(n < 0):
return 0
else:
return seq[n]+iter(n-1)
return iter(len(seq)-1)
这个函数和上面的思路类似,不过有一点不一样,那就是上一个函数中的辅助函数使用了尾递归,而这个是普通递归。
为什么要说递归呢,还是因为前面提到的,函数式语言中没有循环,所以熟练运用递归并优化递归就是一个必须技能,学习函数式编程也不能跳过递归的学习。
仔细观察两个函数会发现,第一个函数的返回值是
iter(len(seq)-1,[])
而第二个是
seq[n]+iter(n-1)
区别在第一个返回值只有函数本身,而第二个则包含了一个seq[n]+。
如果n非常大,那么第二种写法将会非常低效,因为函数需要运行到n=0后不断往回走不断与seq[n]相加。而第一种写法则没有返回的过程,运行更快。
同时,在第二种写法中,因为最后注定要往回走,所以前面的数据必须保留,这样n非常大的时候保留的数据就会非常多,多到一定程度后会栈溢出。而第一种写法将数据全部储存在了变量中,不会存在栈溢出的问题。
上面就是python函数式编程中一些比较基础的东西:递归、匿名函数和返回值。这些不仅可以用在python中,其它任何一个支持函数式的语言中都可以用到。
在学习python函数式编程的时候,不要关注python,要关注函数,后者才是真正的重点。
函数式编程也远不止是上面说的这些,还有continuation passing style(CPS),柯里化,闭包等技术,有兴趣深入学习的话可以了解一下scheme等“更函数”的语言,python支持的函数式编程并不能完全体现函数式编程的思想。