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

# def fn4(i):
#     if i % 3 == 0:
#         return True    
#     return False

def fn4(i):
    return i % 3 == 0
        
# print(fn(fn4 , l))

# fn4是作为参数传递进filter()函数中
# 而fn4实际上只有一个作用,就是作为filter()的参数
# filter()调用完毕以后,fn4就已经没用

filter()

filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中
参数:
1.函数,根据该函数来过滤序列(可迭代的结构)
2.需要过滤的序列(可迭代的结构)
返回值:
过滤后的新序列(可迭代的结构)

匿名函数 lambda 函数表达式 (语法糖)

lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式

语法:lambda 参数列表 : 返回值

匿名函数一般都是作为参数使用,其他地方一般不会使用

def fn5(a , b):
    return a + b

# (lambda a,b : a + b)(10,20)
# 也可以将匿名函数赋值给一个变量,一般不会这么做
fn6 = lambda a,b : a + b
# print(fn6(10,30))


r = filter(lambda i : i > 5 , l)
# print(list(r))

map()

map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回

l = [1,2,3,4,5,6,7,8,9,10]

r = map(lambda i : i ** 2 , l)

# print(list(r))

sort()

该方法用来对列表中的元素进行排序
sort()方法默认是直接比较列表中的元素的大小
在sort()可以接收一个关键字参数 , key
key需要一个函数作为参数,当设置了函数作为参数
每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小

l = ['bb','aaaa','c','ddddddddd','fff']
# l.sort(key=len)

l = [2,5,'1',3,'6','4']
l.sort(key=int)
# print(l)

sorted()

这个函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序
并且使用sorted()排序不会影响原来的对象,而是返回一个新对象

l = [2,5,'1',3,'6','4']
# l = "123765816742634781"

print('排序前:',l)
print(sorted(l,key=int))
print('排序后:',l)

闭包

将函数作为返回值返回,也是一种高阶函数
这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量
可以将一些私有的数据藏到的闭包中

def fn():

    a = 10

    # 函数内部再定义一个函数
    def inner():
        print('我是fn2' , a)

    # 将内部函数 inner作为返回值返回   
    return inner

# r是一个函数,是调用fn()后返回的函数
# 这个函数实在fn()内部定义,并不是全局函数
# 所以这个函数总是能访问到fn()函数内的变量
r = fn()    

# r()

求多个数的平均值

nums = [50,30,20,10,77]

# sum()用来求一个列表中所有元素的和
print(sum(nums)/len(nums))

形成闭包的要件
① 函数嵌套
② 将内部函数作为返回值返回
③ 内部函数必须要使用到外部函数的变量

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))

装饰器

希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕
我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
① 如果要修改的函数过多,修改起来会比较麻烦
② 并且不方便后期的维护
③ 并且这样做会违反开闭原则(OCP)
程序的设计,要求开发对程序的扩展,要关闭对程序的修改

# 创建几个函数

def add(a , b):
    '''
        求任意两个数的和
    '''
    r = a + b
    return r


def mul(a , b):
    '''
        求任意两个数的积
    '''
    r = a * b
    return r    

# r = add(123,456)
# print(r)

# 我们希望在不修改原函数的情况下,来对函数进行扩展
def fn():
    print('我是fn函数....')

# 只需要根据现有的函数,来创建一个新的函数
def fn2():
    print('函数开始执行~~~')
    fn()
    print('函数执行结束~~~')

# fn2()    

def new_add(a,b):
    print('计算开始~~~')
    r = add(a,b)
    print('计算结束~~~')
    return r

# r = new_add(111,222)    
# print(r)

上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了
但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了
为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数

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)

# r = f()
# r = f2(123,456)
# r = f3(123,456)
# print(r)
# 向begin_end()这种函数我们就称它为装饰器

通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
在开发中,我们都是通过装饰器来扩展函数的功能的
在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
可以同时为一个函数指定多个装饰器,这样函数将会按照从内向外的顺序被装饰

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()

猜你喜欢

转载自blog.csdn.net/weixin_51313763/article/details/124683308