(小甲鱼python)函数笔记合集十二 函数(XI)总结 python高阶函数、functools -- 高阶函数、偏函数(@wraps装饰器)等详解

一、基础复习

  1. 函数的基本用法 创建和调用函数 函数的形参与实参等等
  2. 函数的几种参数 位置参数、关键字参数、默认参数等
  3. 函数的收集参数*args **args 解包参数详解
  4. 函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解
  5. 函数的闭包(工厂函数)
  6. 函数装饰器、语法糖、函数作为参数传递给另一个函数、统计传入函数的运行时间等等详解
  7. lambda()函数表达式、map()、filter()函数详解
  8. 生成器的定义、使用和产生生成器的两种方法详解
  9. 函数的递归、递归和迭代的区别详解
  10. python实现汉诺塔详解(主要通过函数的递归实现)
  11. python函数的函数文档、类型注释、内省详解

二、高阶函数

高阶函数:函数可以作为变量传来传去,即自由传递,当一个函数接受另一个函数作为参数的时候,那个时候这种函数我们就把它称之为高阶函数。

1.高阶函数的定义
例1:
讲装饰器的时候,time_master()将myfunc()函数作为参数使用,可以说time_master()是一个高阶函数。
在已学过的函数中,map(),filter()是高阶函数,min(),max(),salty()也可以算是高阶函数,因为它们有一个key参数,接受的正是一个函数对象。

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

2.functools – 高阶函数

高阶函数是函数式编程的灵魂所在,所以python专程搞了一个模块叫做functools,它包含了非常多实用的高阶函数以及装饰器。

例2:reduce函数
functools.reduce(function, iterable[, initializer])
将 iterable 可迭代对象中的元素依次传递到第一个参数指定的函数中,最终返回累积的结果。

例如, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 是计算 ((((1+2)+3)+4)+5) 的值。左边参数 x 是累加值,而右边的参数 y 则是来自 iterable 的更新值。

>>> def add(x,y):
	return x+y

>>> import functools
>>> functools.reduce(add,[1,2,3,4,5])    
15
>>> add(add(add(add(1,2),3),4),5)  # 等价于functools.reduce(add,[1,2,3,4,5]) 
15
>>> 
>>> functools.reduce(lambda x,y:x*y, range(1,11))  # 10的阶乘
3628800
>>> 

3.偏函数

偏函数是指对指定的函数进行二次包装,通常是将现有的函数部分参数预先给绑定,从而得到一个新的函数,该函数我们称之为偏函数。

偏函数的作用就是将一个函数的多个参数给拆分,多次进行传递的样子。
例3:partial函数
functools.partial(func, /, *args, **keywords)
返回一个偏函数,当被调用时,其行为类似于 func 函数附带位置参数 args 和关键字参数 keywords 被调用。

>>> import functools
>>> square=functools.partial(pow,exp=2)
>>> square(2)
4
>>> square(3)
9
>>> cube=functools.partial(pow,exp=3)
>>> cube(2)
8
>>> cube(3)
27

4.@wraps装饰器
例4:普通闭包函数
装饰器的例子

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

结果:

>>> 
================ RESTART: E:\xiaojiayu code\051讲:高阶函数(XII).py ================
开始运行程序...
I love FishC.
结束程序运行...
一共耗费了2.08秒。
>>> 
>>> myfunc.__name__   #name的名字是call_func,而不是myfunc
'call_func'

例5:@wraps装饰器
@functools.wraps(func) 真正的函数是通过func这个函数传入,我们把真正的函数给作为参数传给这个wraps。

import time
import functools

def time_master(func):
@functools.wraps(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. __ name__ 的名字变为myfunc

>>> 
================ RESTART: E:\xiaojiayu code\051讲:高阶函数(XII).py ================
开始运行程序...
I love FishC.
结束程序运行...
一共耗费了2.02秒。
>>> 
>>> myfunc.__name__  # name的名字变为myfunc
'myfunc'
>>> 

课后题:
1.偏函数的实现原理是?
答:闭包。
解析:
偏函数是对指定函数的二次包装,通常是将现有函数的部分参数预先绑定,从而得到一个新的函数,该函数就称为偏函数。
下面代码是偏函数的实现原理(只需要知道它是闭包原理,下面代码大致看得懂就可以,不要求掌握):

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

2.请将下面闭包代码改用偏函数来实现?

>>> def power(exp):
...     def exp_of(base):
...         return base ** exp
...     return exp_of
...
>>> square = power(2)
>>> cube = power(3)
>>> square
.exp_of at 0x000001CF6A1FAF70>
>>> square(2)
4
>>> square(5)
25
>>> cube(2)
8
>>> cube(5)
125

答:

>>> square = functools.partial(pow, exp=2)
>>> square(2)
4
>>> square(3)
9
>>> cube = functools.partial(pow, exp=3)
>>> cube(2)
8
>>> cube(3)
27

解析:pow() 函数需要两个参数,这里我们通过偏函数先指定其中的 exp 参数,然后第二个参数在实际调用的时候再进行传递,这就是偏函数的 “延迟” 效果。
3.请使用偏函数,基于 print() 函数打造一个新的 pr() 函数,使其实现效果如下:

>>> pr("I", "love", "FishC.")
I@love@FishC.#

答:

>>> import functools
>>> pr = functools.partial(print, sep='@', end='#')
>>> pr("I", "love", "FishC.")
I@love@FishC.#

4.请修改下面代码,使得执行 test.name 语句后,得到的结果是 ‘test’,而非 ‘call_func’。

>>> def myfunc(func):
...     def call_func():
...         func()
...     return call_func
...
>>> @myfunc
... def test():
...     print("test~")
...
>>> test()
test~
>>> test.__name__
'call_func'

答:

>>> import functools
>>> def myfunc(func):
...     @functools.wraps(func)
...     def call_func():
...         func()
...     return call_func
...
>>> @myfunc
... def test():
...     print("test~")
...
>>> test()
test~
>>> test.__name__
'test'

题目来自小甲鱼python函数(XI)

你可能感兴趣的:(小甲鱼课程笔记,python,python)