python闭包函数和装饰器

python闭包函数和装饰器

闭包函数

闭包的特点就是内部函数引用了外部函数中的变量
# 闭包函数的两大特征
1.闭:定义在函数内部的函数
2.包:内部函数使用了外层函数名称空间中的名字
    #代码示例:
    def outer():
    name = 'python'
    def inner():
        print(name)
    return inner

    index = outer()
    index()
    
'闭包中被内部函数引用的变量,不会因为外部函数结束而被释放掉,而是一直存在内存中,直到内部函数被调用结束'

闭包函数的实际应用

#闭包好处:
  1. 保护变量
  2. 可以让一个变量常驻内存
  3. 迭代器
    __iter__() 可迭代对象. 获取迭代器
    __next__() + __iter__() 迭代器

  特点:
    1. 惰性机制
    2. 只能向前
    3. 节省内存
  for循环的内部就是迭代器

'闭包函数是给函数体传参的另外一种方式'
#函数体传参的方式1:形参
def index(username):
    print(username)
index('mark')

#函数体传参的方式2:闭包
def outer():
    username = 'jason'
    def index():
        print(username)  
    return index
res = outer()


装饰器简介

# 装饰器的本质
  在不改变被装饰对象原有的'调用方式''内部代码'
  的情况下给被装饰对象添加新的功能
# 装饰器的原则
      对扩展开放
      对修改封闭
        
    #实质: 是一个函数

    #参数:是你要装饰的函数名(并非函数调用)

    #返回:是装饰完的函数名(也非函数调用)

    #作用:为已经存在的对象添加额外的功能

    #特点:不需要对对象做任何的代码上的变动

    
    
# 代码示例:
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)  # 两个时间戳的差值就是函数的执行时间

简易版本的装饰器

直接通过传参的方式
    缺陷1:
        代码写死了 无法统计其他函数的执行时间
        能否解决?
            可以!  将函数名通过形参的形式传入
    缺陷2:
        封装成函数之后 调用方式改变了 不符合装饰器原则

#代码示例:
import time
def get_time(func):
    start_time = time.time()  # 函数执行之前获取一个时间戳
    func()
    end_time = time.time()  # 函数执行之后获取一个时间戳
    print(end_time - start_time)  # 两个时间戳的差值就是函数的执行时间
def home():
    time.sleep(3)
    print('from home')

get_time(home)	#	from home 3.0071964263916016

'第一种直接给函数体传参的方式无法实现装饰器'

#代码示例:
import time
def index():
    time.sleep(1)
    print('from index')
def home():
    time.sleep(3)
    print('from home')
print(home)
def outer(func):  # 真正的index被outer局部名称空间存储了
    def get_time():
        start_time = time.time()  # 函数执行之前获取一个时间戳
        func()  # 调用了真正的index函数
        end_time = time.time()  # 函数执行之后获取一个时间戳
        print(end_time - start_time)  # 两个时间戳的差值就是函数的执行时间
    return get_time

# res = outer(index)  # 左侧的res就是一个普通的变量名
# res()

# index = outer(index)
# index()  # 看似调用的index其实调用的是get_time
# print(index)  # 全局名称空间中的index指向的是get_time函数体代码



# 简易版装饰器
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()

进阶版本装饰器

def outer(index):	
    def inner(*args,**kwargs):	#解决参数问题
        start_time = time.time()
        index()	
        end_time =time.time()
        print(end_time - start_time)
    return inner	

完整版本装饰器

'解决返回值的问题'
#代码示例:
import time
def index():
    time.sleep(1)
    print('from index')
def outer(index):
    def inner(*args,**kwargs):
        start_time = time.time()
        res=index(*args,**kwargs) #这里执行真正的index
        end_time =time.time()
        print(end_time - start_time)
        return #这里返回真正index的返回值
    return inner

index = outer(index)
index()

装饰器模板

'''编写装饰器其实有一套固定的代码 不需要做任何理解'''
def outer(func_name):  # func_name用于接收被装饰的对象(函数)
    def inner(*args, **kwargs):
        print('执行被装饰函数之前 可以做的额外操作')
        res = func_name(*args, **kwargs)  # 执行真正的被装饰函数
        print('执行被装饰函数之后 可以做的额外操作')
        return res  # 返回真正函数的返回值
    return inner

装饰器的语法糖

# 让代码编写的更加好看、简洁!!!

#无参数的语法糖
import time
def show_time(func):
    def inner():  #内部参数
        start_time =time.time()
        func() #调用函数
        end_time=time.time()
        print('服务器响应时间:',end_time-start_time)
    return inner

@show_time #等价于func=show_time(func)
def func():
    print('执行用例')
    time.sleep(1)
#调用函数
func() 


#有参数的语法糖
import time #时间模块
def have_para(name): #参数名,执行者变量
    def show_time(func): #函数名调用变量
        def inner():#内部函数,函数体
            start_time =time.time()
            func()  #调用func()函数
            end_time=time.time()
            print('服务器响应时间:',end_time-start_time)
            print('执行者:',name)
        return inner  #返回inner对象
    return show_time #返回show_time对象

@have_para('wendy') #等价于func=have_para('wendy')
def func():
    print('执行用例')
    time.sleep(1)
func()

'''
语法糖内部原理
    1.使用的时候最好紧跟在被装饰对象的上方
    2.语法糖会自动将下面紧挨着的函数名传给@后面的函数调用
'''

装饰器修复技术

# 做到比真的还要真  但是本质其实没有变
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')
@outer
def home():
    '''这是home函数的注释'''
    print('from home')

help(home)  # help可以查看指定函数的注释信息

home()
index()

posted @   洛阳城门听风雨  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示