博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

5.高阶函数

(1)由于参数 x, y和 f 都可以任意传入,如果 f 传入其他函数,就可以得到不同的返回值。

 

 (2)map映射

map()是 Python 内置的高阶函数,它接收一个函数f和一个list,并通过把函数f依次作用在 list的每个元素上,得到一个新的 list 并返回。

 

 利用map()函数,可以把一个 list 转换为另一个 list,只需要传入转换函数。

由于list包含的元素可以是任何类型,因此,map()不仅仅可以处理只包含数值的 list,事实上它可以处理包含任意类型的 list,只要传入的函数f可以处理这种数据类型。

(3)reduce折叠

reduce()函数接收的参数和 map()类似,一个函数f,一个list,但reduce()传入的函数f必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。

 

 reduce()还可以接收第3个可选参数,作为计算的初始值。

(4)filter过滤

filter()函数接收一个函数f和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。

 

 利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字符串:

 

 (5)sorted():对list进行排序

 

 但sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素x, y,如果x应该排在y的前面,返回-1,如果x应该排在y的后面,返回1。如果x和y相等,返回0。

 

 (6)Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数!

 

 请注意区分返回函数和返回值:

 

 在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问:

(7)闭包

内部函数中引用了外层函数的变量(enclosing作用域的变量),然后返回内层函数的情况。

闭包的作用是封装和代码复用。

传递的是参数

 

传递的是函数

 

 

 

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

返回函数不要引用任何循环变量,或者后续会发生变化的变量。

 

 (8)匿名函数lambda

 

 通过对比可以看出,匿名函数 lambda x: x * x 实际上就是:

def f(x):

    return x * x

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

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

使用匿名函数,可以不必定义函数名,直接创建一个函数对象,很多时候可以简化代码:

 

 返回函数的时候,也可以返回匿名函数:

 

 6.装饰器

(1)decorator本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。

使用 decorator 用Python提供的@语法,这样可以避免手动编写f=decorate(f)这样的代码。

(2)装饰器用来装饰函数,返回一个函数对象

被装饰函数标识符指向返回的函数对象   

 

 (3)传入函数,含有两个参数

 

 (4)@log的定义

 

 但是,对于参数不是一个的函数,调用将报错。@log写死了只含一个参数的返回函数。

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

可变参数*args表示任何多个无名参数,它是一个tuple;**kwargs表示关键字参数,它是一个dict。并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前。

 

 (6)@performance,它可以打印出函数调用的时间。

计算函数调用的时间可以记录调用前后的当前时间戳,然后计算两个时间戳的差。

 

 (7)对于被装饰的函数,log打印的语句是不能变的(除了函数名)。

如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时,log函数本身就需要传入'INFO'或'DEBUG'这样的参数:

 

 所以,带参数的log函数首先返回一个decorator函数,再让这个decorator函数接收my_func并返回新函数:

而且wrapper(*args, **kw)要调用外层参数prefix,所以无法拆开

 

 (8)区别

 

 可见,由于decorator返回的新函数函数名已经不是'f2',而是@log内部定义的'wrapper'。这对于那些依赖函数名的代码就会失效。decorator还改变了函数的__doc__等其它属性。如果要让调用者看不出一个函数经过了@decorator的“改造”,就需要把原函数的一些属性复制到新函数中:

 

 这样写decorator很不方便,因为我们也很难把原函数的所有必要属性都一个一个复制到新函数上,所以Python内置的functools可以用来自动化完成这个“复制”的任务:

 

 (9)当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。

比如,int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:

但int()函数也提供额外的base参数,默认为10。如果传入base参数,就可以做N进制转换:

 

 假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

 

 functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:

 

 所以,functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。

 
 

 

 
posted on 2022-01-20 19:27    阅读(46)  评论(0)    收藏  举报