Python 3、函数式编程

    xiaoxiao2021-04-18  50

    ☆函数式编程

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


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

    f = abs f(-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 * x map(f, [1, 2, 3, 4, 5])

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

    def f(x, y): return x+y reduce(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())>0 filter(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 0 sorted([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 g x = 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 fs f1, f2, f3 = count() #现在调用f1 f1() ==>9 f2() ==>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 x myabs(-1) ==> 1 myags(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 @log def factorial(n): return reduce(lambda x,y: x*y, range(1,n+1)) print factorial(10) ==>call factorial()... ==>3628800

    但是

    @log def add(x, y): return x+y print 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_deocrator def my_func(): pass

    python完善decorator:


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

    import functools int2 = functools.partial(int, base=2) int2('10000') ==>16
    转载请注明原文地址: https://ju.6miu.com/read-674675.html

    最新回复(0)