Python学习第四十六天—函数12(高阶函数)

[复制链接]
15271953841 发表于 2024-3-10 11:08:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

×
高阶函数:higher-order function,函数可以当作变量一样传来传去的,自由传递,当一共函数接收另一个函数作为参数的时侯,那么这个时候,这种函数我们就把它解释为高阶函数。
在学习装饰器的时候,当时代码是这样写的:

import time
def time_master(func):        (这里的time_master将myfunc函数作为函数使用,那么我们说time_master是一个高阶函数。还学过map,filter,还有min,max salty也算是高阶函数,因为它们有一个key参数,接收的正是一个函数对象。)
    def call_func():
        print("开始运行程序...")
        start = time.time()
        func()
        stop = time.time()
        print("结束程序运行...")
        print(f"一共耗费了{(stop-start):.2f}秒。")
    return call_func
        
def myfunc():
    time.sleep(2)
    print("I love FishC")

myfunc = time_master(myfunc)
myfunc()

一、        那么高阶函数是函数是编程的灵魂所在,Python为此也搞了一个模块functools,这里包含很多实用的高阶函数以及装饰器。
ef add(x,y):
    return x + y

import functools
functools.reduce(add,[1,2,3,4,5])     (ruduce的第一个参数指定一个函数,这个函数必须指定两个参数;第二个参数是可迭代对象,ruduce的作用就是将可迭代对象中的元素依次传递到第一个参数指定的函数中,最终返回累计的结果。)
15
add(add(add(add(1,2),3),4),5)
15
functools.reduce(lambda x,y : x*y,range(1,11))    (求10的阶乘:10!=10×9×8×7×6×5×4×3×2×1,lambda匿名函数一句话搞定函数,没必要去定义一个函数)
3628800
如果非要定义一个函数的话,像这样:
def factIter(x,y):
    return x * y

functools.reduce(factIter,range(1,11))
3628800
二、        偏函数:
是对指定的函数进行二次包装,通常是将现有的函数部分参数预先给绑定了,从而得一个新的函数,然后该函数我们称之为偏函数,作用:将一个函数的多个参数拆分多次进行传递的样子。)partial是预先指定一部分参数,就不要再输入了。

square = functools.partial(pow,exp=2)      (pow是内置函数,计算一个数的次幂)
square(2)
4
square(3)
9
cube = functools.partial(pow,exp=3)
cube(2)
8
cube(3)
27
实现原理大致等价于下面这个闭包,相比之下,偏函数就更简单一些:
def partial(func, /, *args, **keywords):
    def newfunc(*fargs,**fkeywords):
        newkeywords = {**keywords, **fkeywords}
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

myfunc = partial(pow,exp=2)
myfunc(2)
4
myfunc(3)
9
myfunc = partial(pow,exp=3)
myfunc(2)
8
myfunc(3)
27
三、@wraps装饰器
编辑模式下:

import time
def time_master(func):
    def call_func():
        print("开始运行程序...")
        start = time.time()
        func()
        stop = time.time()
        print("结束程序运行...")
        print(f"一共耗费了{(stop-start):.2f}秒。")
    return call_func

@time_master             (这是一个装饰器)
def myfunc():
    time.sleep(2)
    print("I love FishC")

myfunc()                      (这个程序执行,完全是调用myfunc来实现的,但有个副作用)
run运行后,在互动模式下:
===================== RESTART: D:/谷兴武/创客/python学习/高级函数2.py =====================
开始运行程序...
I love FishC
结束程序运行...
一共耗费了2.03秒。
myfunc.__name__        (副作用的体现:myfunc的名字不叫myfunc,而是叫call_func)
'call_func'         
上面装饰器只是一个语法糖,它实际上的代码是等同于:
编辑模式下:

import time

def time_master(func):
    def call_func():
        print("开始运行程序...")
        start = time.time()
        func()
        stop = time.time()
        print("结束程序运行...")
        print(f"一共耗费了{(stop-start):.2f}秒。")
    return call_func
        
def myfunc():
    time.sleep(2)
    print("I love FishC")

myfunc = time_master(myfunc)
myfunc()
由于闭包的设计,这里调用myfunc函数,其实相当于调用time_master函数,然后传入myfunc作为它的函数,而调用time_master函数其实是在调用call_func函数,所以上面装饰器程序的最后,使用name索性进行内省的时候,就发现它的真面目就现出来了,(myfunc.__name__        (副作用的体现:myfunc的名字不叫myfunc,而是叫call_func)
'call_func'      ),这是装饰器的副作用。
   
但是大佬们的眼睛容不得沙子,于是发明了wraps装饰器来装饰装饰器:
import time
import functools      (要用到functools模块,所以要先导入它)

def time_master(func):
    @functools.wraps(func)    (这一步必须放在闭包真正调用的函数上面),我们真正的函数是通过这func这个参数传递进去的,我们把这个真正函数作为参数,传给这个wraps
    def call_func():
        print("开始运行程序...")
        start = time.time()
        func()
        stop = time.time()
        print("结束程序运行...")
        print(f"一共耗费了{(stop-start):.2f}秒。")
    return call_func

def myfunc():
    time.sleep(2)
    print("I love FishC")

myfunc = time_master(myfunc)
myfunc()
这样我们去run Module它,在互动模式下:
===================== RESTART: D:/谷兴武/创客/python学习/高级函数3.py =====================
开始运行程序...
I love FishC
结束程序运行...
一共耗费了2.06秒。
myfunc.__name__
'myfunc'     (你会发现它的副作用就没有了,myfunc还是myfunc.)

QQ客服返回顶部