python入门学习之函数式编程

一 前言

  初次接触函数式编程是在学习分布式计算的时候,那时候对map/reduce是不明觉厉,也没有懂多少原理方面的东西。python中的函数式编程也算是初步了解一下map/reduce。所谓函数式编程,本质上是可以归结为面向过程的程序设计,但是它的思想很接近数学计算。它比一般的编程范式要更抽象,而且纯粹的函数式编程语言编写的函数是没有变量的,只要确定了输入,那也就确定了输出。它的另外一个特点就是把函数本身作为参数传入到另一个函数中,允许返回一个函数。

二 高阶函数(high-order function)

  在python中,函数名本质上也是一个变量。我们可以将一个函数名赋值给一个变量,再通过这个变量来调用函数。在使用python面向过程的程序设计中,一个带有变量的函数是很普遍的设计,但是如果这个变量是一个函数,那么这个带有变量的函数我们就称之为高阶函数了。

  一个简单的高阶函数示例:

def fun(n): return n+1def highorder(x, y, f): return f(x)+f(y)

上面定义的highorder就是一个高阶函数,它是可以在参数中接收其他函数的函数。

三 map/reduce

  有了上面的高阶函数基础,现在再来理解map/reduce就很容易了。map函数接收两个参数,一个是函数,另一个是iterable。map将函数依次作用在iterable的每一个元素上,并把结果作为新的iterator返回。

  看下面的示例:

def fun(n): return n*2m=map(fun, [1,2,3,4,5])print(m)e:\study\python>python hello_python.py[2, 4, 6, 8, 10]

  map把函数fun依次作用在列表的每一个元素上,就得到了[2,4,6,8,10]。

  如果嫌定义一个fun函数比较麻烦,可以使用lambda来进行简化,如下:

m=map(lambda n:n*2, [1,2,3,4,5])

  再看reduce的用法。reduce同map一样,也是将一个函数依次作用在一个序列上,但是要求这个函数必须接收两个函数。reduce再把函数作用在前两个参数的结果与下一个序列的元素上。

  下面就用reduce来实现一个序列求和运算,见下例:

def add(x,y): return x+yr=reduce(add, [1,2,3,4,5])print(r)e:\study\python>python hello_python.py15

  它的lambda版本为:

r=reduce(lambda x,y:x+y, [1,2,3,4,5])

四 返回函数

  在前面就已经表述过函数是可以被赋值给一个变量的,那么既然函数可以返回一个变量,当然也是可以返回一个函数的。别看返回变量和返回函数本质上区别不大,但是这种返回函数的机制却在应用中有着极大的作用。

  来看下面的示例:

def wrapper(*param): def calc(): sum=0 for x in param: sum=sum+x return sum return calc;f=wrapper(1,2,3,4,5)print(f())e:\study\python>python hello_python.py15

  定义一个包裹函数wrapper,接收不定数量个参数。在调用此函数后,其会返回一个内部定义的函数,这个函数要在真正调用它时才会执行。另外还要注意的是,calc函数中访问的数据是由wrapper带进来的,并且这些参数会与calc被保存在一起,我们称之为“闭包”(closure)。

五 闭包(closure)

  初次接触闭包,对其并不是十分的理解。仍以四中的代码作为示例。

  wrapper是一个函数,包括不定个数的参数param。比较特殊的地方是这个函数体中还定义了一个新的函数calc,这个新函数的函数体内正引用了一个外部函数wrapper的参数,也就是说,外部函数传递过来的参数已经和calc函数绑定到了一起,形成了一个新函数。我们可以把param看成是这个新函数的一个配置信息。配置信息如果不一样,那函数的输出当然也就不一样了。

  为了更好的理解闭包,看以下代码示例:

def wrapper(conf): def calc(n): return conf+n return calcf1=wrapper(1)f2=wrapper(2)print(f1(100))print(f2(100))e:\study\python>python hello_python.py101102

  分析上述代码,调用wrapper(1)时会返回一个函数,并且这个函数的配置信息是conf的值为1。再调用wrapper(2)时会返回另外一个函数,并且这个函数的配置信息是conf的值为2。所以在随后的我们都传入100参数来调用f1和f2时得到的结果为101和102,其根本原因就在于两个函数的配置信息不一样。

  值得我们注意的是,并不是外部函数的所有信息都会被内部函数做为配置信息,只有外部函数的参数才会被内部函数作为配置信息。至于外部函数的局部变量,就不会被做为配置信息了。

    

六 装饰器(decorator)

  发明decorator的初衷是为了解决在不修改原有函数代码的情况下,在函数调用前后增加其他功能,比如打印日志等。decorator本质上就是一个返回函数的高阶函数,看下面这个打印日志的decorator,代码如下:

def decorator(func): def wrapper(): print(“before invoked:”) func() print(“after invoked:”) return wrapper def func(): print(“func invoked:”) f=decorator(func)f()e:\study\python>python hello_python.pybefore invoked:func invoked:after invoked:

  上述代码给func定义了一个装饰器,在调用这个装饰器时返回一个函数,在这个函数中加上需要的代码后再调用func。但这里有一个问题,那就是原来可以直接调用func,现如今却要调用f了。要解决这个问题很容易,因为在python中函数是可以赋值给一个变量的,只需要将f改成func就可以了。如下所示:

func=decorator(func)func()

  python中为实现这个机制提供了一个语法:@。在func前加上@decorator即可,相当于执行了func=decorator(func),这样就解决了使用相同的名字来调用增加功能后的代码。如下所示:

def decorator(func): def wrapper(): print(“before invoked:”) func() print(“after invoked:”) return wrapper @decoratordef func(): print(“func invoked:”) func()

  另外还有如何给decorator增加参数以及如何修改wrapper的__name__属性为func的内容,这里就不讲述了。

七 偏函数(partial function)

  何谓偏函数?偏函数就是给函数增加默认参数后的函数。在python中,可以使用functools.partial来生成一个函数的偏函数。拿python中的int()做示例,int()函数默认是按十进制转换,如果想生成一个按8进制转换的偏函数,可以如下实现:

print(int(‘12345’))int8=functools.partial(int, base=8)print(int8(‘12345’))

八 总结

  在这篇文章中,主要讲述了函数式编程中的几个基本概念。个人感觉最难理解的就是decorator了,特别是其中的所谓配置信息。如有错误之处,敬请留言!!!

以上就是python入门学习之函数式编程的内容,更多相关文章请关注php中文网(www.php1.cn)!

Posted in 未分类

发表评论