闭包函数与装饰器

闭包函数

# 闭包函数的两大特征
1.闭:定义在函数的内部
2.包:内部函数使用外层函数名称空间的名字
def func():
    name = 'jasom'
    def inner():
        print(name)
    return inner
name = 999
res = func()
res()  # jason

闭包函数实际应用

# 闭包函数是给函数体传参的另一种方式 
# 函数体传参的方式1:形参
def func(a):
    print(a)
func(79)  # 79
# 函数体传参方式2:闭包
 def outer(a):
        def inner():
            print(a)  # 使用的时形参传进来的值
        return inner
res = outer(5)
res()  # 5
'''
内层函数可以接受外层函数 函数体代码定义值,也可以接收外层函数形参传进来的值,且不受全局名称的影响
''' 

装饰器

# 装饰器,在不改变被装饰函数函数体代码以及调用方式的情况下,给函数增加新的功能
装饰器原则:对扩展开放,对修改封闭


'''函数装饰器模板'''
def outer(func_name):  # func_name用于接收被装饰的对象(函数)
    def inner(*args, **kwargs):
        print('执行被装饰函数之前 可以做的额外操作')
        res = func_name(*args, **kwargs)  # 执行真正的被装饰函数
        print('执行被装饰函数之后 可以做的额外操作')
        return res  # 返回真正函数的返回值
    return inner



## 接下来就一步步的将装饰器推导出来

# 1.给函数增加新的功能
def func():
    print('func')
import time
stert_time = time.time()
func()
end_timg = time.time()
print(end_time-start_time)
'''
2.我们给这个函数增加了一个计时的功能,,但是还是有一个问题,那就是,这段代码只能在原位置执行,太死板不够灵活,所以我们可以将这段代码写进一个函数中,来达到让这段代码可随时调用的目的
'''
def get_time():
    start_time = time.time()
    func()
    end_timg = time.time()
    print(end_time-start_time)	
get_time()  # 可以查看函数func的运行时间

# 3.问题又出现了,这个函数写死了,我们只能查看固定函数func()的运行时间,所以我们需要解决这个问题
解决方法:将函数名作为实参传进函数
def outer(func_name):
    start_time = time.time()
    func_name()
    end_timg = time.time()
    print(end_time-start_time)	

# 4.函数装饰器:在不改变被装饰函数函数体代码以及调用方式的情况下,给函数增加新的功能,上面的函数跟装饰器相比还是有一些缺陷
	1.调用方式改变了
    2.被装饰函数无法接收参数
    # 4.1 解决调用方法被改变的问题
    def outer(func_name):
        def inner():
            start_time = time.time()
            func_name()
            end_timg = time.time()
            print(end_time-start_time)
        return inner
	func = outer(func)  # 被装饰func()的全局名称,在这里被替换掉
    func()  # 相当于inner()
    # 4.2 解决被装饰函数无法接受参数的问题
    def outer(func_name):
        def inner(*args,**kwargs):
            start_time = time.time()
            res = func_name(*args,**kwargs) # 接收返回值
            end_timg = time.time()
            print(end_time-start_time)
            return res
        return inner

装饰器语法糖

# 装饰器语法糖的作用只是让代码看起来更加好看和简介
def outer(func_name):
	def inner(*args,**kwargs):
		start_time = time.time()
		res = func_name(*args,**kwargs) 
    	end_timg = time.time()
		print(end_time-start_time)
		return res
	return inner
@outer  # 等价于 index = outer(index)
def index():
    print('hello world')

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

装饰器修复技术

def outer(func_name):
	def inner(*args,**kwargs):
		start_time = time.time()
		res = func_name(*args,**kwargs) 
    	end_timg = time.time()
		print(end_time-start_time)
		return res
	return inner
@outer  
def index():
    print('hello world')
print(index)  #<function outer.<locals>.inner at 0x000001D782E43B70>
'''
不难发现,当我们打印被装饰函数时,发现,他的地址是inner()函数的地址,而装饰器修复技术就是用来解决这一问题的
'''
from functools import wraps # 第一步
def outer(func_name):
     @wraps(func_name)  # 第二步
	def inner(*args,**kwargs):
		start_time = time.time()
		res = func_name(*args,**kwargs) 
    	end_timg = time.time()
		print(end_time-start_time)
		return res
	return inner
@outer  
def index():
    print('hello world')
print(index)  #<function index at 0x0000019F9BEB3B70>

练习

点击展开

flag = False
d = {'jason':'123'}
def outer(func_name):
    def inner(*args,**kwargs):
        global flag
        # 如果已经登陆过,就直接执行被装饰函数
        if flag:
           res = func_name(*args,**kwargs)
           return res
        # 为登录过,就进行登录
        else:
            user_name = input('请输入用户名:').strip()
            user_pwd = input('请输入密码:').strip()
            if d.get(user_name) == user_pwd:
                flag = True
                res = func_name(*args,**kwargs)
                return res
            else:
                print('用户名或者密码错误')
    return inner
@outer
def index(a):
    print(a)
    return a+1
@outer
def index2(b):
    print('hello world')
    return b
index(1)
index2(8)
posted @   名字只需六字  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示