Welcome!!!

F

伞兵一号,申请出战

闭包函数和装饰器

闭包函数和装饰器

闭包函数(重要)

# 闭包函数的两大特性
	1. 闭:定义在函数内部的函数
    2. 包:内部函数使用了外部函数名称空间中的名字
eg:
    def outer():
        x = 1
        def inner():  # 定义在函数内部的函数
            print(x)  # 调用了外部函数名称空间的变量
        return inner  # 外部函数返回内部函数名
    res = outer()
    res()
运行结果:
    1

闭包函数实际应用

# 闭包函数是给函数体传参的另外一种方式
# 函数体传参方式1:形参传值
# def func(username):
#     print(username)
# func('petter')  # 把函数体需要的形参通过实参传过去

# 函数体传参方式2:闭包
eg:
    def outer(x):
    # x = 1
        def inner():  
            print(x)  # 直接调用外部函数名称空间的绑定的形参
    return inner  
    res = outer(1)  # 给外层函数传参
    res()
运行结果:
    1

装饰器简介

# 装饰器的本质
	在不改变被装饰对象原有的'调用方式''内部代码'的情况下给被装饰对象添加新功能
# 装饰器的原则
	对拓展开放
    对修改封闭
# 需求:统一函数的执行时间
import time
def index():
    time.sleep(3)
    print('from index')
'''给index函数增加了一个统计执行时间的功能'''
start_time = time.time()  # 函数执行之前获取一个时间戳
index()
end_time = time.time()  # 函数执行之后获取一个时间戳
print(end_time - start_time)  # 两个时间戳的差值就是函数的执行时间
输出结果:
    from index
	3.004551887512207

简易版本装饰器

# 装饰器实现上述需求
eg:
    def outer(func_name):  # 1. 定义外部函数
        def inner():  # 3.定义内部函数
            start_time = time.time()  # 7. 获取函数运行前的时间戳
            func_name()  # 8. 调用函数,内部函数调用外部函数绑定的形参,由于第2步形参传值,func_name与index临时绑定到一起且这里是先调用outer函数再赋值,所以func_name绑定的是上面的函数名index,即调用函数index()
            end_time = time.time()  # 9. 获取函数运行后的时间戳
            print(end_time - start_time)  # 输出函数运行前后时间戳的差值
        return inner  # 4. 把内部函数的函数名返回出去
    index = outer(index)  # 2. 调用外部函数  # 5. 定义变量名index,让index指向outer的返回值
    index()  # 6. 调用函数,由于index指向inner,所以index()等价于inner(),即调用函数inner()
运行结果:
    from index
	3.0023038387298584

完整版装饰器

上述简易版装饰器还有两个点有问题,我们回想函数的语法结构,可以看到,上述装饰器在index函数有参数传递和返回值时无法实现,完整版的装饰器其实就是解决了这两个问题
eg:
    import time
    def index(username):
        time.sleep(3)
        return username
    # 简易版装饰器
    def outer(func_name):
        def inner(*args, **kwargs):  # 定义可变长形参,无论什么值传过来都可以接收,无论原函数有无参数都不会报错
            start_time = time.time()
            res = func_name(*args, **kwargs)  # 这里也要定义可变长形参,这里还要搞个变量接收原函数的返回值
            end_time = time.time()
            print(end_time - start_time)
            return res  # 这里把原函数的返回值返回出去,原函数没有返回值返回的是None,这样无论原函数有无返回值都不会报错
        return inner
    index = outer(index)
    res = index('这里参数随便传,反正不报错')
    print(res)
运行结果:
    3.0157086849212646
	这里参数随便传,反正不报错

装饰器模板(重要)

其实根据上面的代码,把原函数不存在的功能全删了就是模板
def outer(func_name):  # func_name用于接收被装饰的对象(函数)
    def inner(*args, **kwargs):
        '''原函数被执行前的操作写这里'''
        res = func_name(*args, **kwargs)  # 执行被装饰对象
        '''原函数被执行后的操作写这里'''
        return res  # 返回被装饰对象的返回值
    return inner  # 返回内部函数名,供全局调用

装饰器语法糖

# 作用仅仅是让代码编写的更加好看、简洁
eg:
    '''上接完整版装饰器'''
    @outer  # 相当于执行了 my_age = outer(my_age)
    def my_age(age):
        time.sleep(3)
        return age
    res = my_age(18)
    print(res)
运行结果:
    3.0101282596588135
	18
"""
语法糖内部原理
    1.使用的时候最好紧跟在被装饰对象的上方
    2.语法糖会自动将下面紧挨着的函数名传给@后面的函数调用
"""

装饰器修复技术

eg:
    from functools import wraps
    def outer(func_name):
        @wraps(func_name)
        def inner(*args, **kwargs):
            print('下面这货被装饰了')
            res = func_name(*args, **kwargs)
            return res
        return inner
    @outer
    def index():
        '''这是真函数的注释'''
        print('from index')  
    index()
    print(index)
    help(index)
   	运行结果:
        下面这货被装饰了
        from index
        <function index at 0x01592030>
        Help on function index in module __main__:

        index()
            这是真函数的注释
'''wraps模块warps关键字可以把真函数的属性提取出来,赋值给装饰器,达到以假乱真的地步'''

posted @   程序猿伞兵一号  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示