python学习之高阶函数

一、函数式编程

  • 在Python中,函数是一等对象
    - 一等对象一般都会具有如下特点:
    ① 对象是在运行时创建的
    ② 能赋值给变量或作为数据结构中的元素
    ③ 能作为参数传递
    ④ 能作为返回值返回
    就是将一个一个的功能通过函数来完成,python支持函数式编程,但python不是函数式编程语言。

二、什么是高阶函数

接收函数作为参数,或者将函数作为返回值的函数是高阶函数
当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数。

  • 高阶函数至少要符合以下两个特点中的一个
    ① 接收一个或多个函数作为参数
    ② 将函数作为返回值返回

为什么需要高阶函数呢?
例子:定义一个函数,可以将指定列表中的所有的偶数,或所有奇数,或大于5的数等,保存到一个新的列表中返回

用普通的函数实现

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def fn(lst):
    # 创建一个新列表
    new_list = []
    # 对列表进行筛选
    for n in lst:
        # # 判断n的奇偶
        # if n % 2 == 0:
        #     new_list.append(n)
        # # 取奇数
        # if n % 2 != 0:
        #     new_list.append(n)
        # # 取大于5的数
        # if n > 5:
        #     new_list.append(n)
        if not fn2(n):
            new_list.append(n)

    # 返回新列表
    return new_list


print(fn(l))

或:

def fn(lst):
    def fn2(i):
        if i % 2 == 0:
            return True
        return False

    def fn3(i):
        if i > 5:
            return True
        return False

    # 创建一个新列表
    new_list = []
    # 对列表进行筛选
    for n in lst:
        # # 判断n的奇偶
        if fn2(n):
            new_list.append(n)
        # 大于5的数
        if fn3(n):
            new_list.append(n)

    # 返回新列表
    return new_list


print(fn(l))

使用高阶函数实现:

# 在函数内部在定义一个函数,用来检查一个任意数字是否是偶数
def fn2(i):
    if i % 2 == 0:
        return True
    return False


def fn3(i):
    if i > 5:
        return True
    return False


def fn(func, lst):
    # 创建一个新列表
    new_list = []
    # 对列表进行筛选
    for n in lst:
        if func(n):
            new_list.append(n)

    # 返回新列表
    return new_list

# 当传fn2函数作为参数时,实际上是将fn2的代码传递
print(fn(fn2, l)) # [2, 4, 6, 8, 10]
print(fn(fn3, l)) # [6, 7, 8, 9, 10]

三、filter()函数

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

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


# 在函数内部在定义一个函数,用来检查一个任意数字是否是偶数
def fn2(i):
    if i % 2 == 0:
        return True
    return False


r = filter(fn2, l)
print(list(r))  #[2, 4, 6, 8, 10]

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

四、匿名函数

匿名函数 lambda 函数表达式 (语法糖)
lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式
语法:lambda 参数列表 : 返回值
匿名函数一般都是作为参数使用,其他地方一般不会使用.

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

print(fn5(123, 456))  # 579

# 用lambda来代替这个函数
lambda a, b: a + b
print((lambda a, b: a + b)(123,456))  # 579

# 将lambda表达式,赋值给一个变量
result  = lambda a, b: a + b
print(result(123,456)) #

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

# 第一次改造
def fn4(i):
    return i % 3 == 0


# 改造lambda
lambda i: i % 3 == 0

# r = filter(fn4(), l)
r = filter(lambda i: i % 3 == 0, l)
print(list(r))

五、map函数

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

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

r = map(lambda i : i+1 , l)
print(r)  # <map object at 0x7fec094ce0f0>
print(list(r)) # [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

六、sort函数

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

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


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


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

七、sorted()

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

l = [2, 5, '1', 3, '6', '4']
print('排序前:', l)
print(sorted(l, key=int))
print('排序后:', l)   

控制台打印;
排序前: [2, 5, '1', 3, '6', '4']
['1', 2, 3, '4', 5, '6']
排序后: [2, 5, '1', 3, '6', '4']

八、闭包

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

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

# 外部函数
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))

九、装饰器

1、引入装饰器
举例: 希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕

def add(a , b):
    '''
        求任意两个数的和
    '''
    print("开始计算...")
    r = a + b
    print('计算结束...')
    return r


def mul(a , b):
    '''
        求任意两个数的积
    '''
    print("开始计算...")
    r = a * b
    print('计算结束...')
    return r   

弊端:如果多个函数需要打印计算开始和计算结束,那么就要给每一个函数都要添加两行语句。

我们希望在不修改原函数的情况下,来对函数进行扩展

def fn():
    print('我是fn函数....')

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

fn2()
控制台打印:
函数开始执行~~~
我是fn函数....
函数执行结束~~~


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

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

控制台打印结果:
计算开始~~~
计算结束~~~
333

将new_add变成一个通用的函数,不用对每一个需要扩展的函数,都要创建一个新的函数。

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

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


def mul(a , b):
    '''
        求任意两个数的积
    '''
    r = a * b
    return 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()这种函数我们就称它为装饰器
通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
在开发中,我们都是通过装饰器来扩展函数的功能的。(将旧函数作为参数传递给新的函数,新函数对旧函数进行升级)
在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰

@begin_end
def say_hello():
    print('大家好~~~')

say_hello()

@fn3
@begin_end
def say_hello():
    print('大家好~~~')

say_hello()  
先执行begin_end装饰,在执行fn3装饰。
参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

FamilyYan

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值