函数装饰器

装饰器是什么

  • ‘装饰’指被装饰对象添加新的功能,‘器’代指器具/工具,装饰器与被装饰对象均可是可以任意调用的对象。
  • 装饰器是由 名称空间 函数对象 闭包函数组合使用的一种方法
    在这里插入图片描述

装饰器的用途

  • 装饰器核心: 能够在不改变被“装饰对象内部代码”和“原有调用方式”的基础上给被装饰对象添加额外的功能

装饰器的实现

  • 装饰器可以分为: 无参装饰器和有参装饰器两种,两者实现原理一样

无参装饰器实现过程

在这里插入图片描述

1.给函数添加统计执行时间的功能
import time
def outer(func):  # func 指向函数名func1
    def get_time():
        start_time = time.time()
        func()
        end_time = time.time()
        print('函数运行时间:%s'%(end_time - start_time))
    return get_time  # 将get_time函数名返回出去

def func1():
    print('from func1')
 
func1 = outer(func1)  # outer(func1函数名)
# 左侧的变量名func1指代的是函数名get_time
func1()
  • 这时,我们通过上方代码成功给func1添加了一个新功能,但还没完,我们可以发现,若函数是一个有参函数,便无法正常运行
    在这里插入图片描述
2.解决函数参数问题
import time
def outer(func):  # func 指向函数名func1
    def get_time(*args,**kwargs):  
        start_time = time.time()
        func(*args,**kwargs) # 2.元组或字典形式的参数在这又会重新打散进行传值
        end_time = time.time()
        print('函数运行时间:%s'%(end_time - start_time))
    return get_time  # 将get_time函数名返回出去

def func1(a, b):
    print('from func1 %s:%s'%(a, b))
 
func1 = outer(func1)  # outer(func1函数名)
# 左侧的变量名func1指代的是函数名get_time
func1(11, 22)  # 1.接受的参数会打包成元组 字典的形式
  • 通过前面学习的可变长参数,就能够将函数参数问题完美解决,并且不管该装饰器所装饰的对象是否需要参数,需要多少参数,运行都是没有问题
  • 这时我们还忽略的一个问题,原函数返回值问题,也是需要我们解决
    在这里插入图片描述
3. 解决返回值问题
import time
def outer(func):  # func 指向函数名func1
    def get_time(*args,**kwargs):  
        start_time = time.time()
        res = func(*args,**kwargs) # func函数的返回值赋值给res
        end_time = time.time()
        print('函数运行时间:%s'%(end_time - start_time))
        return res  # 将res的值返回
    return get_time  # 将get_time函数名返回出去

def func1(a, b):
    print('from func1 %s:%s'%(a, b))
    return a b
 
func1 = outer(func1)  # outer(func1函数名)
# 左侧的变量名func1指代的是函数名get_time
func1(11, 22)  # 1.接受的参数会打包成元组 字典的形式
  • 到了这一步,我们已经基于开放封闭原则,在不修改被装饰对象func1的源代码和调用方式的前期下,给func1添加了一个新功能,实现了一个简单的无参装饰器
  • 该装饰器还可以用来装饰其他带参数或者不带参数的函数
    在这里插入图片描述
4.无参装饰器固定模板
def outer(func):
    def inner(*args, **kwargs):
        print('执行函数之前可以添加的额外功能')
        res = func(*args, **kwargs)  # 执行被装饰的函数
        print('执行函数之后可以添加的额外功能')
        return res  # 将被装饰函数执行之后的返回值返回
    return inner

装饰器语法糖

我们在使用用装饰器,方式一:'func1 = outer(func1)'这种形式是不可缺少的,如果装饰器使用过多,不可避免的会照成代码冗余,为了解决这个问题,python解释器提供了一种专门装饰器语法来取代
    @outer  # @ + 装饰器名称
使用注意事项:
"""
装饰器语法糖是写规范
    语法糖必须紧贴在被装饰对象的上方
装饰器语法糖内部原理
    会自动将下面紧贴着的被装饰对象名字当做参数传给装饰器函数调用
"""

并且如果我们有多个装饰器,可以叠加多个

@deco3
@deco2
@deco1
def index():
    pass

上述代码语义如下:
    index=deco3(deco2(deco1(index)))
'''
定义自下而上  运行自上而下
'''

在这里插入图片描述

有参装饰器的实现

  • 基于无参装饰器实现原理,我们可以再来实现一个用来为被装饰对象添加认证功能的装饰器,实现基本形式如下
def login_auth(func):
    def auth(*args,**kwargs):
        # 2.校验用户名和密码是否正确
        # 数据的校验方式可以切换多种
        if source_data == 'file':
            # 从文件中获取用户数据并比对
            print('file文件获取')
        elif source_data == 'MySQL':
            # 从MySQL数据库中获取数据比对
            print('MySQL数据库获取')
        elif source_data == 'postgreSQL':
            # 从postgreSQL数据库中获取数据对比
            print('postgreSQL数据库获取')
        else:
            print('用户名或密码错误 无法执行函数')
        return auth
  • 通过上述代码 我们可以发现,auth函数内还需要一个source_data参数。
  • 而此时不管是login_auth函数还是auth函数都无法直接传参,因此我们剩下一种办法,在login_auth函数外面再包一层,专门用来传参
def outer(source_data):
    # source_data = 'file'
    def login_auth(func):
        def auth(*args,**kwargs):
            # 2.校验用户名和密码是否正确
            # 数据的校验方式可以切换多种
            if source_data == 'file':
                # 从文件中获取用户数据并比对
                print('file文件获取')
            elif source_data == 'MySQL':
                # 从MySQL数据库中获取数据比对
                print('MySQL数据库获取')
            elif source_data == 'postgreSQL':
                # 从postgreSQL数据库中获取数据对比
                print('postgreSQL数据库获取')
            else:
                print('用户名或密码错误 无法执行函数')
        return auth
    return login_auth

在这里插入图片描述

  • 到此我们就实现了一个有参装饰器,使用方法如下
#先调用outer('file'),得到@login_auth,login_auth是一个闭包函数,包含了对外部作用域名字source_data的引用,@login_auth的语法意义与无参装饰器一样
@outer('file')
def index():
    print('from index')
@outer('MySQL')
def home():
    print('from home')

index()
home()
有参装饰器模板
def outer(参数1,参数2):
	def werper(func):
        def inner(*args, **kwargs):
            print('执行函数之前可以添加的额外功能')
            res = func(*args, **kwargs)  # 执行被装饰的函数
            print('执行函数之后可以添加的额外功能')
            return res  # 将被装饰函数执行之后的返回值返回
        return inner
   	return werper

在这里插入图片描述

装饰器修复技术

  • 我们可以用help(函数名)来查看函数文档注释,但对于被装饰之后的函数,查看的文档注释并不是原文档注释
@timer
def home(name):
    time.sleep(3)
    print('Welcome to the home page',name)
 
print(help(home))
'''
打印结果:
 
Help on function inner in module __main__:
 
inner(*args, **kwargs)
 
None
'''

在这里插入图片描述

解决办法(装饰器究极模板)
from functools import wraps
def outer(func):
    @wraps(func)  # 修复技术就是为了让被装饰对象更加不容易被察觉装饰了
    def inner(*args, **kwargs):
        print('执行函数之前可以添加的额外功能')
        res = func(*args, **kwargs)  # 执行被装饰的函数
        print('执行函数之后可以添加的额外功能')
        return res  # 将被装饰函数执行之后的返回值返回
    return inner
@outer  # index = outer(index)
def index():
    print('from index')
print(index)
help(index)
  • 到此,我们用help查看函数名属性和注释就是原函数的内容了
    在这里插入图片描述
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值