Loading... python的函数部分——高阶函数,闭包和装饰器 <!--more--> --- ## 高阶函数 - 高阶函数满足:接收函数作为参数,或者将函数作为返回值的函数是高阶函数 - 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数 - 例如一个列表中的元素,想要取出其中一些满足条件的元素 ```python # 创建一个列表 l = [1,2,3,4,5,6,7,8,9,10] # 定义一个函数 # 可以将指定列表中的所有的偶数,保存到一个新的列表中返回 # 定义一个函数,用来检查一个任意的数字是否是偶数 def fn2(i) : if i % 2 == 0 : return True return False # 这个函数用来检查指定的数字是否大于5 def fn3(i): if i > 5 : return True return False def fn(func , lst) : ''' fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回 参数: lst:要进行筛选的列表 ''' # 创建一个新列表 new_list = [] # 对列表进行筛选 for n in lst : # 判断n的奇偶 if func(n) : new_list.append(n) # if n > 5 : # new_list.append(n) # 返回新列表 return new_list ``` - 对于上图所示代码,只需要调用fn函数并且传入选择的函数和要被选择的列表即可。 ## 闭包 - 刚刚说到高阶函数可以是将函数作为参数传入,还有一种返回函数的情况,闭包就是利用了这个。 - 假设我们需要一个求平均数的函数,我可能会这么写 ```python # 首先创建一个列表 nums = [] def average(n): ''' 将n插入到数列中,并且计算平均数。 ''' nums.append(n) return sum(nums) / len(nums) print(average(10)) # 输出10 print(average(10)) # 输出10 print(average(20)) # 输出13.333333333 ``` - 但是设想如果有一个人在代码里加入了一个重名的nums变量,就会覆盖我们设置的nums变量,例如 ```python # 首先创建一个列表 nums = [] def average(n): ''' 将n插入到数列中,并且计算平均数。 ''' nums.append(n) return sum(nums) / len(nums) print(average(10)) # 输出10 print(average(10)) # 输出10 nums = [] print(average(20)) # 输出20 ``` - 这样我们的程序就会被破坏,这时就轮到闭包出场 ```python def make_averager(): # 创建一个列表,用来保存数值 nums = [] # 创建一个函数,用来计算平均值 def averager(n) : # 将n添加到列表中 nums.append(n) # 求平均值 return sum(nums)/len(nums) return averager averager = make_averager() print(averager(10)) print(averager(20)) print(averager(30)) print(averager(40)) ``` - 这样的话,nums列表对外来说就是不可见的,在全局中修改/创建nums变量也不会有任何问题。 ## 装饰器 - 我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题 ① 如果要修改的函数过多,修改起来会比较麻烦 ② 并且不方便后期的维护 ③ 并且这样做会违反开闭原则(OCP) 程序的设计,要求开发对程序的扩展,要关闭对程序的修改 - 如果在不修改原函数的情况下,对原函数进行扩展,可以用下列方法: ```python def fn(): print('我是fn函数....') # 只需要根据现有的函数,来创建一个新的函数 def fn2(): print('函数开始执行~~~') fn() print('函数执行结束~~~') ``` - 上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了 - 但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了 - 为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数,于是产生了下列代码 ```python def begin_end(old): ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数: old 要扩展的函数对象 ''' # 创建一个新函数 def new_function(*args , **kwargs): print('开始执行~~~~') # 调用被扩展的函数 result = old(*args , **kwargs) print('执行结束~~~~') # 返回函数的执行结果 return result # 返回新函数 return new_function f = begin_end(fn) f2 = begin_end(add) f3 = begin_end(mul) # 向begin_end()这种函数我们就称它为装饰器 # 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展 # 在开发中,我们都是通过装饰器来扩展函数的功能的 # 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数 # 可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰 ``` - 例如“begin_end()”这种函数我们就称它为装饰器 - 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展 - 在开发中,我们都是通过装饰器来扩展函数的功能的 - 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数 - 可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰 ```python def fn3(old): ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数: old 要扩展的函数对象 ''' # 创建一个新函数 def new_function(*args , **kwargs): print('fn3装饰~开始执行~~~~') # 调用被扩展的函数 result = old(*args , **kwargs) print('fn3装饰~执行结束~~~~') # 返回函数的执行结果 return result # 返回新函数 return new_function @fn3 @begin_end def say_hello(): print('大家好~~~') say_hello() ``` --- 参考:阿里云大学 Last modification:April 6, 2020 © Allow specification reprint Like 如果觉得我的文章对你有用,请随意赞赏