函数式编程
函数式不等于函数,c语言是函数编程,python是函数式编程,比c语言更抽象,同时也更高级。
函数式编程把计算视为了函数,而不是计算机指令,支持高阶函数,代码简介。
python支持高阶函数:函数可以作为变量传入
python支持闭包:返回函数
高阶函数
变量可以指向一个函数:
f=abs
print f(-20)
函数名和普通的变量名没有区别,只是它指向了一个函数而已。
高阶函数就是能够接受函数作为参数的一种函数:
f=abs
def add(x,y,f):
return f(x)+f(y)
print add(-1,-2,abs)
结果为3,函数add的变量f就是函数abs,由于add函数的入参中涉及到了一个函数,所以add就是一个高阶函数。
python为什么要这样设计呢,难受是不支持函数嵌套调用?
再来一个例子吧:
import math as m
def add(x, y, f):
return f(x) + f(y)
print add(25, 9, m.sqrt)
这遍之后感觉简单的函数嵌套调用这样写的话确实要清晰一点,目前这种用法的优点及场景我还无法考究,但是应该是肯定有优势的,比起c语言来。话说这个import好像就是模块的意思,后面详细讲解,这个很实用的,有助于提高编码质量。
内置高阶函数
我理解都这些函数都可以用我们现有的基础功能函数去完成,不过既然是血高级语言,那就越简单越好,所有就有了如下几个内置的高阶函数:
rL=map(function,L)L中每个成员执行function功能,结果放在列表rL中;
r=reduce(function,L)L中对前两个成员执行function功能,得到一个成员来替换掉L中的前两个成员,以此类推,直到L中只有一个成员为止,操作结果存放在r中;
rL=filter(function,L)L中每个成员执行function功能,结果为true咋把L中对应成员放进rL中。
现在我们以最后一个filter为例:
import math as m
def is_sqr(x):
return m.sqrt(x)%1==0
print filter(is_sqr, range(1, 101))
L=[]
for x in range(1,101):
if is_sqr(x)==True:
L.append(x)
print L
第2~4行:使用filter实现功能;
第5~8行:使用基础方法实现filter功能。
函数中返回函数
def calc(lst):
def f():
sum=1
for i in lst:
sum=sum+i
return sum
return f
f = calc([1, 2, 3, 4])
print f()
看到上面的代码了吧,这个的玩儿法就是在函数A里面申明一个函数B,然后函数A的返回就是指向函数B的这个变量。以上面代码为例:
第1行:申明函数calc,入参为一个列表lst
第2行:在函数calc的函数体中申明函数f,入参为空
第3~6行:函数f的函数体,对一个列表做累加操作,并返回结构
第7行:函数calc返回函数f
它这个东西和c语言比较,由于申明函数的时候不需要指明函数类型,也就是函数返回值,所以用的时候随便搞一个变量指向一个函数的返回结果就可以了,即f=calc([1,2,3,4]),这个时候如果calc()
的执行结果是返回一个函数,那么再用f()就可以得到结果。
综上:这个感觉有点像C语言的钩子函数,函数的返回值实际上是一个地址,这个地址指向另一个函数,由于python是高级语言,没有指针,所以他只能通过在一个函数体中去申明一个函数并返回该函数的方式来实现钩子函数的功能。
闭包
前文提到的返回函数的模式下:
def A(lst):
def B():
do something with lst
renturn xx
return B
外层函数A中入参lst在内层函数B中被调用,A的返回值又是函数B,这种就称为B包。换句话说,就是B 只能申明在A的内部才能运行,如果申明在A的外部,通过A调用B这种函数嵌套调用的方式可以实现的都不叫闭包。
也因此就出现一个闭包的限制条件,变量lst在调用过程中都不能被改变。
来一段多层的代码:
def count():
fs = []
for i in range(1, 4):
def f(i):
def g():
return i*i
return g
fs.append(f(i))
return fs
f1, f2, f3 = count()
print f1(), f2(), f3()
这是真的恶心,函数count()中申明f(i),然后f(i)中再申明g(),count()返回的列表fs中的成员其实就是g()
匿名函数
这个东西有点像C语言里面的宏定义函数,又不像,一起看一下吧,这里面用到关键字是lambda
c=lambda x:x*x
for i in range(1,11):
print c(i)
我们用一个变量c指向这个匿名函数,该函数入参为x,出参为x*x,通过c(value)调用,在入参是一个函数的地方可以用此匿名函数以简化代码,便于代码的阅读,现在来根据前文的内置高阶函数map()为例,首先温习一下map()函数吧,map(functional.List)该函数功能是提取每个List里面的成员执行functionnal功能,然后返回到一个队列中(应该是tuple):
L=[1,2,3,4,5,6]
print map(lambda x:x*x,L)
这里的lambda就相当于:
def f(x):
retunr x*x
print map(f,L)
这里自己去体会吧,感觉用处多多,都是为了代码简介应运而生的。
装饰器
这个东西我理解很重要,建议别自己写,去找现成的装饰器,然后@装饰器名称在需要装饰的函数之前就可以了,此处不详细说明了,我的理解按照一个良好编码风格的C语言玩家的习惯,这个东西目前暂时看不到需要用的地方,不过还是挺方便的,这个东西。
偏函数
这个东西感觉是系统级的函数才会使用,他的目的就是隐藏一部分入参,让一个函数的参数表变的简单,举个例子:
A函数有3个入参,A(x,y,z)通过偏函数,我们可以把A变成只有一个入参A(x),其余两个参数都默认,这个东西和之前提到的带固定参数指引的函数不是一样吗: A(x,y=1,z=2)
我理解是一样的,这里我们调用A(x)不是也将参数个数简化到1个了吗。
至此,函数、函数式编程已经说完了,下面是不是该说函数调用了,我的意思是目前编码只在一个py文件里,现在要是要是我要在A.py里面调用B.py里面的函数该怎么办呢?下一篇我们就讲解这个了。
好了,我感觉编码好玩儿的地方开始了,马上就会开始面向对象了,作为一个c语言玩家你是不知道我们有多可能能使用类这个东西。