Python 3、函数式编程

来源:互联网 发布:漫画软件推荐 编辑:程序博客网 时间:2024/06/15 21:03

☆函数式编程

函数式编程functional之于函数好比计算之于计算机
支持高阶函数,无变量(Python中的高阶函数有变量)
支持闭包


高阶函数:
变量可以指向函数

f = absf(-20)==>20

能接收函数作为参数的函数称为高阶函数

def add(x, y, f):    return f(x) + f(y)add(-5, 9, abs)==>14

map函数:
map()是一个高阶函数,接收一个函数f,和一个list,并把f作用在list的每个元素上,得到一个新的list并返回

def(x):    return x * xmap(f, [1, 2, 3, 4, 5])

reduce函数:
reduce()函数是一个高阶函数,接收一个函数f,和一个list,其中函数f必须接收两个参数,reduce对list的每个元素及其后的一个元素调用f

def f(x, y):    return x+yreduce(f, [1, 2, 3, 4, 5])==>1+2+3+4+5==>15

reduce还可以接收3个参数,最后一个参数作为计算初始值


filter函数:
filter()函数是一个高阶函数,接收一个函数f,和一个list。
f的作用是对list中每个元素进行判断,返回True或False,
返回值判断为True的元素组成的新的list

#删除None或空字符串def is_not_empty(s):    return s and len(s.strip())>0filter(is_not_empty, ['test', None, '', 'str', '   ', 'END'])==>['test', 'str', 'END']

自定义排序函数:
python内置的sorted()可以作为高阶函数,对list进行排序
不接收函数f作为参数的情况下,进行默认排序

sorted([36, 5, 12, 9, 21])==>[5, 9, 12, 21, 36]

sorted(list, f)
第二个参数f为可选参数,传入排序函数
倒序:

def reversed_cmp(x, y):    if x>y:        return =1    elif x<y:        return 1    return 0sorted([36, 5, 12, 9, 21], reversed_cmp)==>[36, 21, 12, 9, 5]

返回函数:

def f():    print 'call f()...'    #定义函数g    def g():        print 'call g()...'    #返回函数g    return gx = f()==>call f()...x==><function g at 0xa334f235>x()==>call g()...

闭包:
先来一个函数:

def calc_sum(lst):    def lazy_sum():        return sum(lst)    return lazy_sum

注意:没法把lazy_sum移到calc_sum的外部,因为它引用了calc_sum的参数lst
像这种内层函数引用外层函数的变量(参数),然后返回内层函数的情况,称为闭包

闭包的特点:
返回的函数引用了外部函数的局部变量或参数

要正确使用闭包,就要保证引用的局部变量在函数返回后不能变

错误的例子:
希望一次返回3个函数,分别计算1*1, 2*2, 3*3

def count():    fs = []    for i in range(1, 4):        fef f():            return i * i        fs.append(f)    return fsf1, f2, f3 = count()#现在调用f1f1()==>9f2()==>9

外?
原因是当count函数返回3个函数时,变量i已经变成了3,
返回后,f1才被调用,故
所以,返回函数不要引用任何循环变量,或后续会发生变化的变量


匿名函数:
高阶函数接收函数作为参数,可用匿名函数作为参数
以map()为例:

map(lambda x: x*x, [1, 2, 3, 4])==>[1, 4, 9, 16]

其中lambda x: x*x实际上就是

def f(x):    return x*x

关键字lambda表示匿名函数,冒号前的x表示函数参数

匿名函数有个限制就是:只能有一个表达式,不能写return .
返回值就是表达式的结果

变量指向函数时也可以使用匿名函数

myabs = lambda x: -x if x<0 else xmyabs(-1)==> 1myags(1)== 1

decorator装饰器:
问题:想在已定义好的函数中动态地添加功能(如日志记录),怎么办
答:编写一个高阶函数将原函数传入高阶函数并调用。
这个高阶函数就成为 装饰器函数

python中内置@语法,就是为了简化装饰器调用

@new_fn                 def f(x):def f(x):         ==>       return x*2    return x*2          f = new_fn(f)

装饰器的作用:
可以极大地简化代码,避免每个函数编写重复性代码
打印日志:@log
检测性能:@performance
数据库事务:@transaction
URL路由:@post(‘/register’)


无参decorator:
无参,是指高阶函数,除了接受一个函数f,不再接收其他参数

def log(f):    def fn(x):        print 'call', f.__name__, '()...'        return f(x)    return fn@logdef factorial(n):    return reduce(lambda x,y: x*y, range(1,n+1))print factorial(10)==>call factorial()...==>3628800

但是

@logdef add(x, y):    return x+yprint add(1,2)==>TypeError:fn() takes exactly 1 argument(2 given)#因为add()函数传入了两个参数,而,上边`return f(x)`写死了,内层函数只能有一个参数

要让@log自适应任何参数定义的函数,可以利用Python的 *args**kw
保证任意个数参数总能正常调用:

def log(f):    def fn(*args, **kw):        print 'call', f.__name__, '()...'        return f(*args, **kw)    return fn

带参数decorator:
如果有的函数希望log打印出’[Info] call xxx()’,
有的函数希望log打印’[DEBUG] call xxx()’
这时候log函数本身就需要传入’INFO’ 或’DEBUG’,如下:

@log('DEBUG')def my_func():    pass相当于======>翻译成高阶my_func = log('DEBUG')(my_func)#再展开log_decorator = log('DEBUG')my_func = log_decorator(my_func)#也相当于log_decorator = log('DEBUG')@log_deocratordef my_func():    pass

python完善decorator:


偏函数:
还记得int(x, base=10)吗,调用int(x)就默认base=10
其实,int2(x, base=2)就可以默认为二进制了,但是这样也很麻烦去造函数
functools.partial 帮助我们创建偏函数

import functoolsint2 = functools.partial(int, base=2)int2('10000')==>16
1 0