Python 3、函数式编程

本文深入探讨函数式编程的核心概念,包括高阶函数、闭包、匿名函数等,并通过Python实例展示如何应用这些概念实现常见操作,如排序、过滤及使用装饰器增强函数功能。

☆函数式编程

函数式编程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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值