设为首页 收藏本站
查看: 920|回复: 0

[经验分享] [原创]Python入门学习之函数式编程

[复制链接]

尚未签到

发表于 2015-11-29 13:05:13 | 显示全部楼层 |阅读模式
  一 前言
  初次接触函数式编程是在学习分布式计算的时候,那时候对map/reduce是不明觉厉,也没有懂多少原理方面的东西。Python中的函数式编程也算是初步了解一下map/reduce。所谓函数式编程,本质上是可以归结为面向过程的程序设计,但是它的思想很接近数学计算。它比一般的编程范式要更抽象,而且纯粹的函数式编程语言编写的函数是没有变量的,只要确定了输入,那也就确定了输出。它的另外一个特点就是把函数本身作为参数传入到另一个函数中,允许返回一个函数。
  
  二 高阶函数(High-order Function)
  在Python中,函数名本质上也是一个变量。我们可以将一个函数名赋值给一个变量,再通过这个变量来调用函数。在使用python面向过程的程序设计中,一个带有变量的函数是很普遍的设计,但是如果这个变量是一个函数,那么这个带有变量的函数我们就称之为高阶函数了。
  一个简单的高阶函数示例:



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

  上面定义的highorder就是一个高阶函数,它是可以在参数中接收其他函数的函数。
  
  三 Map/Reduce
  有了上面的高阶函数基础,现在再来理解Map/Reduce就很容易了。Map函数接收两个参数,一个是函数,另一个是Iterable。Map将函数依次作用在Iterable的每一个元素上,并把结果作为新的Iterator返回。
  看下面的示例:



def fun(n):
return n*2
m=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+y
r=reduce(add, [1,2,3,4,5])
print(r)
E:\Study\python>python hello_python.py
15

  它的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.py
15

  定义一个包裹函数wrapper,接收不定数量个参数。在调用此函数后,其会返回一个内部定义的函数,这个函数要在真正调用它时才会执行。另外还要注意的是,calc函数中访问的数据是由wrapper带进来的,并且这些参数会与calc被保存在一起,我们称之为“闭包”(closure)。
  
  五 闭包(Closure)
  初次接触闭包,对其并不是十分的理解。仍以四中的代码作为示例。
  wrapper是一个函数,包括不定个数的参数param。比较特殊的地方是这个函数体中还定义了一个新的函数calc,这个新函数的函数体内正引用了一个外部函数wrapper的参数,也就是说,外部函数传递过来的参数已经和calc函数绑定到了一起,形成了一个新函数。我们可以把param看成是这个新函数的一个配置信息。配置信息如果不一样,那函数的输出当然也就不一样了。
  为了更好的理解闭包,看以下代码示例:



def wrapper(conf):
def calc(n):
return conf+n
return calc
f1=wrapper(1)
f2=wrapper(2)
print(f1(100))
print(f2(100))
E:\Study\python>python hello_python.py
101
102

  分析上述代码,调用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.py
Before 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        
@decorator
def 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了,特别是其中的所谓配置信息。如有错误之处,敬请留言!!!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-144933-1-1.html 上篇帖子: Python(2.7.6) ConfigParser 下篇帖子: virtualenv 环境下 Nginx + Flask + Gunicorn+ Supervisor 搭建 Python Web
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表