装饰器、语法糖、修复技术

装饰器

【一】什么是装饰器

  • 装饰器就是为被装饰的对象添加新的功能
  • 器 ---> 代表工具 增加后调用方式不变
  • 在不改变原函数代码和调用方式的基础上增加额外的新功能

【二】装饰器的用途

  • 对上线后的程序进行新功能的增加和修改
  • 给一个功能增加新的需求或者改变原来的程序的运行逻辑

【三】装饰器的分类

【1】有参装饰器

【2】无参装饰器

【四】装饰的原理

闭包函数 + 函数对象的组合使用

无参装饰器

【一】什么是无参装饰器

没有参数的装饰器

【二】推导装饰器的语法

为一段代码增加计时功能

面条版

import time
start_time = time.time()

print("开始")

time.sleep(2)

print("结束")

end_time = time.time()

print(end_time - start_time)


# 开始
# 结束
# 2.003873825073242
函数版
import time
def time_():
    print("开始")
    time.sleep(2)
    print("结束")

start_time = time.time()
time_()
end_time = time.time()

print(end_time - start_time)

# 开始
# 结束
# 2.015000104904175
装饰器版
import time

def time_():
    start_time = time.time()
    print("开始")

    time.sleep(2)

    end_time = time.time()
    print("结束")
    
    return print(end_time - start_time)

def outer(func):
    def inner():
        func()
        
    return inner

abc = outer(time_)
abc()

# 开始
# 结束
# 2.0015313625335693

【三】推导装饰器

【1】无参装饰器模板

# 无参装饰器的模板
def outer(func):
    ''' 
    :param func: 指每一次需要调用传递的函数
    :return:返回值是内嵌函数 inner 的函数内存地址 
    '''
    def inner():
        # 可以加逻辑校验
        # 当符合指定条件后,可以允许执行传递进来的函数
        # 不符合条件的时候不执行函数
        func()
        # 做逻辑校验,func 函数执行后的逻辑

    return inner

abc = outer(abc)
abc()
  • outer(abc)指的是函数outer 在参数为abc时的返回值inner

  • abc()则是内嵌函数inner()

【2】登录校验

user_data_dict = {'username': "qwer", "password": "123"}
def outer(func):
    def inner():
        username = input("username :>>>> ")
        password = input("password :>>>> ")
        # 否则打印失败
        if username == user_data_dict.get('username') and password == user_data_dict.get('password'):
            print(f"登录成功")
            func()
        else:
            print("登录失败")

    return inner


def transform():
    print(f"这是在转账功能")
transform = outer(transform)
transform()

# transform = outer(transform)  # transform  = inner = outer(transform)
# transform()  # transform() = inner() = outer(transform)()

def withdral():
    print(f"这是取款功能")
withdral = outer(withdral)
withdral()

有参装饰器

【1】无参装饰器

无参装饰器无法传递参数

def outer(func):
    def inner():
        func()
    return inner

def transform(username,money):
    print(f"向{username}转账{money}")

transform = outer(transform)
transform()# 报错

【2】有参装饰器

根据指定的位置参数传递参数

def outer(func):
    def inner(username,money):
        func(username,money)
    return inner

def transform(username,money):
    print(f"向{username}转账{money}")

transform = outer(transform)
transform(1,2)

【3】优化

用可变长位置参数和可变长关键字参数接收到函数所需要的所有参数

def outer(func):
    def inner(*args,**kwargs):
        func(*args,**kwargs)
    return inner

def transform(username,money):
    print(f"向{username}转账{money}")

transform = outer(transform)
transform(1,2)

【4】有参装饰器模板

def outer(func):
    def inner(*args, **kwargs):
        func(*args, **kwargs)
    return inner

装饰器语法糖

【1】无参装饰器语法糖

def timer(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(f"总耗时 :>>>> {end - start} s")

    return inner

@timer  # 等效于 transform = timer(transform)
def transform():
    time.sleep(1)

# transform = timer(transform)
# transform()

transform()

【2】有参装饰器语法糖

(1)单语法糖

login_dict = {
    'username':'qwer'
}

def login(func):
    def inner(*args,**kwargs):
        if login_dict.get('username'):
            func(*args,**kwargs)
        else:
            print("用户不存在")
    return inner
@login  # 等效于 transform = timer(transform)
def transform(username,abc):
    print({username},{abc})
# transform = timer(transform)
# transform()

transform(1,2)

(2)多语法糖

login_dict = {'username': None}


def decrator(tag):
    '''

    :param tag: 'login_auth' ---> 登录认证装饰器
    'timer' ---> 返回 计时装饰器
    :return:
    '''
    if tag == "login_auth":
        def login_auth(func):
            def inner(*args, **kwargs):
                if login_dict.get('username'):
                    func(*args, **kwargs)
                else:
                    print(f"请先登录!")
            return inner
        return login_auth
    elif tag == "timer":
        def timer(func):
            def inner(*args, **kwargs):
                start = time.time()
                func(*args, **kwargs)
                end = time.time()
                print(f"总耗时 :>>>> {end - start} s")

            return inner

        return timer


def transform(username, money):
    print(f"{username} | {money}")
    time.sleep(1)

# transform = decrator(tag="login_auth")(transform)
# transform('qwer',123)
# print(transform)

transform = decrator(tag="timer")(transform)
transform('qwer',123)
print(transform)

(3)优化多语法糖

login_dict = {'username': None}


def decrator(tag):
    '''

    :param tag: 'login_auth' ---> 登录认证装饰器
    'timer' ---> 返回 计时装饰器
    :return:
    '''
    if tag == "login_auth":
        def login_auth(func):
            def inner(*args, **kwargs):
                if login_dict.get('username'):
                    func(*args, **kwargs)
                else:
                    print(f"请先登录!")
            return inner
        return login_auth
    elif tag == "timer":
        def timer(func):
            def inner(*args, **kwargs):
                start = time.time()
                func(*args, **kwargs)
                end = time.time()
                print(f"总耗时 :>>>> {end - start} s")

            return inner

        return timer
    else:
        print(f"无参数的",tag)

# @decrator(tag='login_auth')
@decrator(tag='timer')
def transform(username, money):
    print(f"{username} | {money}")
    time.sleep(1)

transform("dream",999)

【3】多层语法糖案例

def a(func):
    # 【二】调用 a 函数触发
    print(1111)
    def inner(*args,**kwargs):
        # 【三】执行 c()
        print(2222)
        func(*args,**kwargs) # 执行 b_inner(c)
         # 【七】结束上面的 b_inner 回来
        print(3333)
    return inner

def b(func):
    # 【一】进来 b 函数
    print(4444)
    def inner(*args,**kwargs):
         # 【四】因为在 a 的 inner 里面调用了 func --> 就是我自己
        print(5555)
        func(*args,**kwargs)
        # 【六】执行完 c 又回来继续走
        print(6666)
    return inner

@a
@b 
# 多层语法糖的时候谁在下先调用谁,但是执行校验的时候是谁在上先校验谁
def c():
    # 【五】回到真正的 c
    print(7777)

# @a 
# @b 
相当于
# c = b(c)
# c = a(c)
# c()


    
执行顺序
4444
1111
2222
5555
7777
6666
3333

'''
# 定义顺序是一个个挨着定义
# 调用顺序是倒着谁在下先调用谁
# c = b(c)
# c = a(c)
# c()
'''

装饰器的修复技术

【一】无修复技术

可以通过help函数来查看函数内部的注释

import time
# 我们可以通过help函数查看函数内部的注释
def timer(func):
    '''
    :param func: 传入的参数
    :return:
    '''
    def inner(*args, **kwargs):
        '''
        :param args: 可变长位置参数
        :param kwargs: 可变长关键字参数
        :return:
        '''
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print(end - start)

    return inner


@timer
def run():
    print(f"run 开始")
    time.sleep(2)
    print(f"run 结束")


print(help(timer))
print(help(run))

#查看函数内部注释 
timer(func)
    :param func: 传入的参数
    :return:

None
Help on function inner in module __main__:

inner(*args, **kwargs)
    :param args: 可变长位置参数
    :param kwargs: 可变长关键字参数
    :return:

None

【二】问题

  • 装饰器其实就是在不改变源代码调用方式的基础上额外增加新功能
  • 别人可以通过help查看内部的注释

【三】有修复技术

从 functools 导入wraps

from functools import wraps

def timer(func):
    '''

    :param func: 传入的参数
    :return:
    '''
    @wraps(func)
    def inner(*args, **kwargs):
        '''
        :param args: 可变长位置参数
        :param kwargs: 可变长关键字参数
        :return:
        '''
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print(end - start)

    return inner


@timer
def run():
    print(f"run 开始")
    time.sleep(2)
    print(f"run 结束")
print('外部函数注释',help(timer))
print('内嵌函数注释',help(run))

# 查看函数内部注释 外部能查看到注释,被包住的内嵌看不到注释
Help on function timer in module __main__:

timer(func)
    :param func: 传入的参数
    :return:

外部函数注释 None
Help on function run in module __main__:

run()

内嵌函数注释 None

posted @   随机昵称yi  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示