Python是一门多范式编程语言,它在很大程度上支持函数式编程。那么什么是函数式编程呢?我的理解是函数的输入和输出都可以是函数的编程方式。当然我理解可能是错的,或者是片面的,本篇就通过搜集一些网上关于python函数式编程的资料,以期能更深入理解下函数式编程。
函数式编程
先来段引用,出自百度百科。
函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。
和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。
和过程化编程相比,函数式编程里函数的计算可随时调用。
函数编程具有如下五个鲜明特点:
- 函数是一等公民:函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。
- 只用表达式不用语句:表达式(expression)是一个单纯的运算过程,总是有返回值;语句(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
- 没有副作用:副作用(side effect)指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。函数式编程强调没有”副作用”,意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。
- 不修改状态:上一点已经提到,函数式编程只是返回新的值,不修改系统变量。因此,不修改变量,也是它的一个重要特点。
- 引用透明性:函数程序通常还加强引用透明性,即如果提供同样的输入,那么函数总是返回同样的结果。就是说,表达式的值不依赖于可以改变值的全局状态。
函数式变成具有以下优点:
- 代码简洁,开发快速
- 接近自然语言,易于理解
- 更方便的代码管理
- 易于”并发编程”
- 代码的热升级
Python函数式编程
高阶函数
输入(参数)可以为函数的函数是高阶函数。例如:1
2
3def add(a, b, f):
return f(a) + f(b)
add(-1, -2, abs)
上面的add函数为自定义的高阶函数。python提供了一些高阶函数,如:map、reduce、filter、sorted等,下面介绍之。
map
天下大势,分久必合,合久必分
,这里的map就是分,举例:求1到100每个整数的平方。
我们传统的思维应该是这样的:1
2
3
4
5l = range(1, 101)
l1 = []
for i in l:
l1.append(i*i)
print l1
用map应该是这样的:1
2
3
4def sq(i)
return i*i
l2 = map(sq, l)
print l2
其思想就是将之前依次每个求平方变为分别求平方,至于map是怎么分别的我就不管了。
或有人说,就这个还用这么费劲,我有更简单的:1
2l3 = [i*i for i in l]
print l3
这个代码量上是简单了,但是本质还是上面的第一种,这只是python为简化此类操作提供的列表生成式。
那接着举例子,看你还有什么简单写法,求1到100的整数之和
。这个最简单的方法就是背过了,呵呵5050,我们来看用reduce的实现。
reduce
map应了分,reduce就应了合。就上面例子我们看reduce怎么做:1
2
3def add(a, b):
return a + b
sum = reduce(add, l)
好了,这就是reduce的使用例子了。正常思维的写法就不上代码了,至于有没有像上面列表生成式那种简单的写法我是不知道。
filter
filter就是过滤器了,从已有列表中过滤出满足条件的。接着上例子列出1到100的所有偶数
,看filter是怎么做的:1
2
3def even(i):
return i%2 == 0
l4 = filter(event, l)
就这么简单,当然列表生成式也可以很简单。
sorted
下面我们来把1到100的整数顺序打乱,使用sorted进行排序。1
2
3
4import random
l = range(1,101)
random.shuffle(l)
sorted(l)
这样会从小到大排序,当然原来的列表顺序是不变的,会输出新列表。
sorted(l, reverse=True)
这样就可以从大到小排序。下面看怎么自定义排序方式:1
2
3
4
5
6
7
8def cmp(a, b):
if a > b:
return -1
elif a < b:
return 1
else:
return 0
sorted(l, cmp=cmp)
要想从大到小排序,就在第一个参数大于第二个参数时返回负数,反之就那样。我来个更兼的写法,顺便引出匿名函数
:1
sorted(l, cmp=lambda x,y:y-x)
匿名函数
先来个例子lambda x,y:x+y
,这里lambda表示匿名函数,空格后冒号前表示匿名函数的参数,冒号后只能有一个表达式,不能有return,表达式的运算结果表示函数的返回值。这样例子的匿名函数就与下面等效:1
2def func(x, y):
return x + y
匿名函数也可以没有参数,也可以作为返回值返回,例如:1
2
3
4def build(x, y):
return lambda: x*x + y*y
f = build(3,4)
c = f() #这时c是25
闭包
内层函数引用了外层函数的变量,然后返回内层函数的情况,称为闭包(closure)。抄个网上的例子:1
2
3
4
5
6
7
8def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
可以试一下什么结果。
闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。
装饰器
python的装饰器(decorator)本质是一个高阶函数,它接收被装饰的函数作为参数,返回一个新瀚抒,这个新函数内部执行了被装饰的函数。下面来个装饰器例子:1
2
3
4
5
6def log(func):
def wrapper(*args, **kw):
print 'before call %s()...'%func.__name__
func(*args,**kw)
print 'after call %s()...'%func.__name__
return wrapper
上面定义了一个装饰器log,下面定义两个函数:1
2
3
4def hello():
print 'hello,world.'
def add(a,b):
print a+b
那么,如何用装饰器来装饰它们呢,请看:1
2
3
4f1 = log(hello)
f2 = log(add)
f1()
f2(3,4)
但是,正常是没有这样用的,一般这样就好了:1
2
3
4
5
6
7
8
9
def hello():
print 'hello,world.'
def add(a,b):
print a+b
hello()
add(3,4)
这下就方便多了。
类装饰器
类装饰器
这个名字是我自己取的,应该是不对的。反正我想表达的意思是在定义一个类的方法时经常会用到的@property、@staticmethod、@classmethod等。直接看例子吧。
@property1
2
3
4
5
6
7
8
9
10
11
12
13
14class Square:
def __init__(self,sideLen):
self.sideLen = sideLen
def perimeter(self):
return self.sideLen*4
def area(self):
return self.sideLen*self.sideLen
#测试
s = Square(5)
print s.sideLen
print s.area
print s.perimeter
@staticmethod1
2
3
4
5
6
7
8class Foo:
def spam(x,y,z):
print x,y,z
#测试
Foo.spam(1,2,3)
f = Foo()
f.spam(3,2,1)
@classmethod1
2
3
4
5
6
7
8
9
10
11class A:
def test(cls):
print cls.__name__
class B:
pass
#测试
A.test()
B.test()
b=B()
b.test()
说明就不说了,我抄的这篇
总结
我看https://www.liaoxuefeng.com关于python函数式编程还有偏函数,先不记录了。