首页 > 其他分享 >装饰器、语法糖、修复技术

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

时间:2024-05-20 12:29:48浏览次数:9  
标签:修复 transform 语法 inner func time print 装饰 def

装饰器

【一】什么是装饰器

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

【二】装饰器的用途

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

【三】装饰器的分类

【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

标签:修复,transform,语法,inner,func,time,print,装饰,def
From: https://www.cnblogs.com/yi416/p/18201640

相关文章

  • 函数对象、装饰器、闭包函数
    函数对象Python中一切皆对象【1】可以直接被引用定义一个函数用一个新的变量名来存,用新的变量名来调用【2】可以作为元素被储存功能字典的函数地址【3】函数可以作为参数传递给另一个函数将函数的内存地址作为参数传递【4】函数的返回值可以是函数直接将函数的内存地址返......
  • Markdown基础语法2024测试
    标题一标题二标题三标题四标题五标题六hr加粗字体b斜体字体i引用内容code超链接ablockquoteol>li有序列表ul>li无须列表pre代码块p表格标题内容居中内容居右col3isright-aligned$1600col2iscentered$12zebrastripe......
  • 当装饰者模式遇上Read Through缓存,一场技术的浪漫邂逅
    在《经验之谈:我为什么选择了这样一个激进的缓存大Key治理方案》一文中,我提到在系统中使用的缓存是旁路缓存模式,有读者朋友问,有没有用到过其他的缓存模式,本文将结合一个我曾经工作中的案例,使用装饰者模式实现ReadThrough缓存模式,助你轻松掌握设计模式和缓存。一、缓存模式不说废......
  • 整理C语言预处理过程语法的实用方法与技巧
    预处理目录预处理一、宏定义数值宏常量字符串宏常量用define宏定义注释符号?程序的编译过程预处理中宏替换和去注释谁先谁后?如何写一个不会出现问题的宏函数do-while-zero结构do-while-zero的评价宏定义中的空格宏只能在main函数上面定义吗?宏的作用范围#undef宏替换是在函数调用......
  • react中的jsx语法
    JSX是JavaScriptXML的缩写,它是一种JavaScript的语法扩展。JSX允许在JavaScript代码中编写类似于XML或HTML的标记结构,用来描述用户界面的结构。 在React应用中,开发者通常使用JSX来定义组件的结构。这样做的好处是,JSX让代码更加直观易读,并且可以轻松地在JavaS......
  • VUE速通(10)Vue3核心语法(2)setup
    1setup概述setup是Vue3中一个新的配置项,值是一个函数,它是CompositionAPI“表演的舞台”,组件中所用到的:数据、方法、计算属性、监视......等等,均配置在setup中。特点如下:setup函数返回的对象中的内容,可直接在模板中使用。setup中访问this是undefined。setup函数会......
  • Spark_DLS语法:
    Spark_DLS语法:目录Spark_DLS语法:1.[Spark]-SQL2.DSL示例3.DSL解析json,csv文件1.printSchema()打印表结构2.studentDF.show(100)默认20条数据3.studentDF.show(false)某些值太长,完整打印每一列的数据4.DSL函数4.DataSource4.1csv:需要手动指定列名和类型4.2jsonparquet格式......
  • python中的装饰器,迭代器,生成器之间的关系
    一、装饰器装饰即修饰,意指为其他函数添加新功能;装饰器的本质就是函数作用是为其他函数添加新功能,如计算该函数运行时长装饰器遵循原则:1.不修改被装饰函数的源代码(开放封闭原则)2.为被装饰函数添加新功能后,不能修改被修饰函数的调用方式装饰器的实现=高阶函数+函数嵌套+......
  • markdown常用语法
    标题Markdown支持两种标题的语法,Setext和atx形式。Setext形式是用底线的形式,利用=(最高阶标题)和-(第二阶标题),例如:ThisisanH1ThisisanH2任何数量的=和-都可以有效果。Atx形式则是在行首插入1到6个#,各对应到标题1到6阶,例如:ThisisanH1ThisisanH2ThisisanH6你......
  • ComfyUI使用基础工作流+面部adapter修复
    json{"last_node_id":13,"last_link_id":19,"nodes":[{"id":6,"type":"CLIPTextEncode","pos":[415,186],"size&qu......