Python学习笔记(四)

来源:互联网 发布:通信算法工程师 工作 编辑:程序博客网 时间:2024/05/16 19:10

Python学习笔记(四)

函数式编程

函数式编程就是一种抽象程度很高的编程范式,函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

1.高阶函数

将函数作为参数的函数叫高阶函数。一个简单的高阶函数:

def add(x, y, f):    return f(x) + f(y)  

几个Python内置的高阶函数:

map

map()函数接收两个参数,一个是函数,一个是Iterablemap将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。通俗点说,传一个函数和一个list进去后,函数作用于list里面的每一个元素之后返回一个新的list。

L= [1,2,3,4,5]def f(x):    return x * xm = map(f,L)print(list(m))print(L)  [1, 4, 9, 16, 25][1, 2, 3, 4, 5]  

由于map()返回的是Iterable对象,因此通过list()函数让它把整个序列都计算出来并返回一个list。

reduce

reduce()把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算

from functools import reducedef fn(x,y):    return x*10 + yprint(reduce(fn,[1,3,5,7,9]))   13579  

filter

filter()函数用于过滤序列,和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

def is_odd(x):    return x%2 == 1L = list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))print(L)  [1, 5, 9, 15]   

删除一个序列中的空元素,相当于过滤一个序列,用到函数strip()

def not_empty(s):    return s and s.strip()L = list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))print(L)  ['A', 'B', 'C']  

sorted

sorted()函数是用来对序列进行排序的函数

print(sorted([36, 5, -12, 9, -21]))  [-21, -12, 5, 9, 36]  

同时它也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序

print(sorted([36, 5, -12, 9, -21], key=abs))  [5, 9, -12, -21, 36]  

要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True

print(sorted([36, 5, -12, 9, -21], key=abs,reverse = True))  [36, -21, -12, 9, 5]  

2.返回函数

函数作为返回值

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

def lazy_sum(*args):    def sum():        ax = 0        for x in args:            ax =  ax + x        return ax    return sumf = lazy_sum(1,2,3,4,5)print(f)print(f())  显示结果:<function lazy_sum.<locals>.sum at 0x00342030>15  

由上可知,当调用lazy_sum()的时候,返回的是求和函数,当调用f()的时候才进行求和

闭包

在上面的例子中,在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种结构叫闭包
当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

f1 = lazy_sum(1,2,3,4,5)f2 = lazy_sum(1,2,3,4,5)print(f1)print(f2)  运行结果:  <function lazy_sum.<locals>.sum at 0x009C2030><function lazy_sum.<locals>.sum at 0x00A17E88>  

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变。

3.匿名函数

匿名函数,就是没用名字的函数,即不需要显示定义。在Python中,对匿名函数提供了有限支持。

f = map(lambda x : x * x ,[1,2,3,4,5])print(list(f))  运行结果:  [1, 4, 9, 16, 25]  

关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不能写return,返回值就是该表达式的结果。
匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

f = lambda x : x * xprint(f(5))  运行结果:  25  

同样,也可以把匿名函数作为返回值返回。

4.装饰器

装饰器的作用是在不修改原来函数的基础上增强函数功能。装饰器也是一个函数,这个函数是将装饰的函数作为参数,并且返回一个函数,定义一个装饰器:

def deco(func):    print("call deco()")    def wrapper():        print("call wrapper()")        func()    return wrapper  

deco函数为装饰器函数,func为被装饰的函数,它被当作参数传入到装饰器中。
借助Python的@语法,把decorator置于函数的定义处:

@decodef bar():    print("call bar()")  

现在调用bar(),打印结果如下:

bar()  运行结果:  call deco()call wrapper()call bar()  

由打印结果可以看出函数的执行顺序:deco–>wrapper–>bar。过程如下:

def deco(func):    print("call deco()")    def wrapper():        print("call wrapper()")        func()    return wrapper@decodef bar():    print("call bar()")运行结果:  call deco()  

由于@deco语法作用,它相当于执行一句代码:

bar = deco(bar)  

它会先调用deco()函数,并将被装饰的函数作为参数传进去,此时bar指向了deco()函数返回的函数wrapper(),bar()函数本身还是存在的。而当调用bar()这句代码的时候相当于调用了wrapper()函数,而在wrapper()内部又调用了bar(),因此函数的执行顺序就是成了deco–>wrapper–>bar。

装饰器的本质就是对闭包的使用。

5.偏函数

此处的偏函数不是数学意义上的偏函数,而是functools模板提供的一个功能,主要作用是降低函数调用的难度。
高阶函数sorted()可以对一个序列进行排序。现在有一个 ['bob', 'about', 'Zoo', 'Credit'],用sorted()对其进行排序 :

print(sorted(['bob', 'about', 'Zoo', 'Credit']))  运行结果:  ['Credit', 'Zoo', 'about', 'bob']  

现在需求是忽略大小写进行排序,这样我们就需要定义一个函数传入到sorted()函数里面去:

def f(str):    return str.lower()  print(sorted(['bob', 'about', 'Zoo', 'Credit'],key = f))  运行结果:  ['about', 'bob', 'Credit', 'Zoo']  

functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义函数f:

import functoolsf= functools.partial(sorted,key = str.lower)print(f(['bob', 'about', 'Zoo', 'Credit']))  运行结果:  ['about', 'bob', 'Credit', 'Zoo']

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

参考资料:廖雪峰的官方网址

原创粉丝点击