装饰器的语法糖及装饰器修复技术

embedded/2024/9/24 7:38:26/

【一】无参装饰器语法糖

  • 没有语法糖的装饰器方法:

def timer(func):def inner():start = time.time()func()end = time.time()print(f"总耗时:{end - start} s")
​return inner
​
​
def transform():time.sleep(2)
​
​
tra = timer(transform)
tra()
  • 有语法糖的:

def timer(func):def inner():start = time.time()func()end = time.time()print(f"总耗时:{end - start} s")
​return inner
​
​
@timer                  # 加一个@timer
def transform():time.sleep(2)
​
​
transform()

【二】有参装饰器的语法糖

  • 有参装饰器

def timer(func):def inner(*args, **kwargs):start = time.time()func(*args, **kwargs)end = time.time()print(f"总耗时:{end - start} s")
​return inner
​
​
@timer
def transform(username, money):print(f'{username} | {money}')time.sleep(2)
​
transform("knight",666)
  • 有参语法糖(单个语法糖)

  • 现在只能使用一种装饰器并且在装饰器中不能切换

login_dict = {'username': 'knight'}
​
​
def login_auth(func):def inner(*args, **kwargs):if login_dict.get('username'):func(*args, **kwargs)else:print(f"请先登录")
​return inner
​
​
def timer(func):def inner(*args, **kwargs):start = time.time()func(*args, **kwargs)end = time.time()print(f"总耗时:{end - start} s")
​return inner
​
​
@login_auth
def transform(username, money):print(f'{username} | {money}')time.sleep(2)
​
​
transform("knight", 666)
  • 多语法糖(这个方法依旧有点麻烦)

login_dict = {'username': 'knight'}
​
​
def decr(tag):'''
​:param tag: 如果返回'login_auth'   ---进入登录认证装饰器: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_authelif 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(2)
​
​
transform = decr(tag='timer')(transform)
transform('knight', 666)
print(transform)
  • 多语法糖优化

login_dict = {'username': 'knight'}
​
​
def decr(tag):'''
​:param tag: 如果返回'login_auth'   ---进入登录认证装饰器: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 innerreturn login_authelif 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
​
​
@decr(tag='login_auth')
def transform(username, money):print(f'{username} | {money}')time.sleep(2)
​
​
transform('knight', 666)

语法糖案例

def dec_a(func):# 【二】调用 dec_a 函数触发print('111')
​def wrapper(*args, **kw):# 【三】执行 main_func()print('222')func(*args, **kw)  # b_wrapper(main_func)# 【七】结束上面的 b_wrapper 回来print('333')
​return wrapper
​
​
def dec_b(func):# 【一】进来 dec_b 函数print('aaa')
​def wrapper(*args, **kw):# 【四】因为在 dec_a 的 wrapper 里面调用了 func --> 就是我自己print('bbb')func(*args, **kw)  # main_func# 【六】执行完 main_func 又回来继续走print('ccc')
​return wrapper
​
​
@dec_a
@dec_b # 多层语法糖的时候谁在下先调用谁,但是执行校验的时候是谁在上先校验谁
def main_func():# 【五】回到真正的 main_funcprint('main_func')
​
'''
# 定义顺序是一个个挨着定义
# 调用顺序是倒着谁在下先调用谁
main_func = dec_b(main_func)
# main_func = b_wrapper (main_func)
main_func = dec_a(main_func)
# main_func = a_wrapper (b_wrapper(main_func))
main_func()
# a_wrapper
​
# aaa
# 111
# 222
# bbb
# main_func
# ccc
# 333
'''
​
main_func()
​
​
# 指定结果打印顺序

【练习】

方法一:

# 定义一个数据字典存储用户数据
user_dict = {'username': 'knight', 'password': '123'}
​
# 分别校验用户名和密码
# 分别是两个装饰器
# 一个负责校验用户名是否存在
def check_username(func):def inner(*args, **kwargs):username_input = input("用户名:").strip()userdict_ = user_dict.get('username_input')if not userdict_ == username_input:print(f"当前用户{username_input}未注册")else:func(*args, **kwargs)
​return inner
​
​
# 一个负责校验密码是否正确
​
​
def check_password(func):def inner(*args, **kwargs):password_input = input("密码:").strip()passworddict_ = user_dict.get('password_input')if passworddict_ != password_input:print(f'密码错误')else:func(*args, **kwargs)
​return inner
​
​
# 只有符合上一个装饰器的条件才能走到下一个装饰器
def transform(username, money):print(f"{username} 转账 {money}")
​
​
transform(username='knight', money=6666)

方法二:语法糖

user_dict = {'username': 'knight', 'password': '123'}def check_user(tag):if tag == 'username':def check_username(func):def inner(*args, **kwargs):username_input = input(f'用户名').strip()username_dict = user_dict.get(username_input)if not username_dict != username_input:print(f"当前用户{username_input}不允许使用")else:func(*args, **kwargs)return innerreturn check_usernameelif tag == 'password':def check_password(func):def inner(*args, **kwargs):password_input = input(f'密码').strip()password_dict = user_dict.get("password")if password_dict != password_input:print(f'密码错误')else:func(*args, **kwargs)return innerreturn check_password@check_user(tag='username')
@check_user(tag='password')
def transform(username, money):print(f"{username} 转账 {money}")transform(username='knight', money=6666)

【三】装饰器的修复技术

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(run))
# 装饰器其实就是在不改变源代码调用方式的基础上额外增加新功能
# 别人就可能通过help查看内部的注释 ---> 把用户名和密码都加进去了

装饰器修复技术

from functools import wrapsdef 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(run))

http://www.ppmy.cn/embedded/7152.html

相关文章

百度AI大会发布的APP Builder和Agent Builder有什么区别

百度在AI大会发布了三款AI工具,包括智能体开发工具AgentBuilder、AI原生应用开发工具AppBuilder、各种尺寸的模型定制工具ModelBuilder 有很多人就问,APP Builder和Agent Builder有什么不一样,怎么那么多builder? 你们就这么理解&#xff…

xss攻击原理与解决方法

概述 XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器 执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列 表,然后向联系人发送虚…

Let’s Encrypt 申请免费https证书(snapd安装)

Let’s Encrypt 最近给域名安装免费的https证书 Let’s Encrypt,发现跟之前的安装方式不太一样,这里记录一下安装过程 https://certbot.eff.org/instructions?wsnginx&oscentosrhel7 https://eff-certbot.readthedocs.io/en/latest/using.html#ng…

Flink学习(七)-单词统计

前言 Flink是流批一体的框架。因此既可以处理以流的方式处理,也可以按批次处理。 一、代码基础格式 //1st 设置执行环境 xxxEnvironment env xxxEnvironment.getEnvironment;//2nd 设置流 DataSource xxxDSenv.xxxx();//3rd 设置转换 Xxx transformation xxxDS.…

MATLAB求和函数

语法 S sum(A) S sum(A,“all”) S sum(A,dim) S sum(A,vecdim) S sum(,outtype) S sum(,nanflag) 说明 示例 S sum(A) 返回沿大小大于 1 的第一个数组维度计算的元素之和。 如果 A 是向量,则 sum(A) 返回元素之和。 如果 A 是矩阵,则 sum(A) 将…

电脑工作者缓解眼部疲劳问题的工具分享

背景 作为以电脑为主要工作工具的人群,特别是开发人员,我们每天都需要长时间紧盯着屏幕,进行代码编写、程序调试、资料查询等工作。这种持续的工作模式无疑给我们的眼睛带来了不小的负担。一天下来,我们常常会感到眼睛干涩、疲劳…

转:Learn Rust the Dangerous Way-系列文章翻译-总述

原文地址 太精彩了,不转不足以表达我的喜爱。 前言 《Learn Rust the Dangerous Way》​cliffle.com/p/dangerust/ 最近发现了一个学习Rust的优秀系列文章,本人准备对该系列文章进行翻译。 本文是《Learn Rust the Dangerous Way》系列文章翻译的第…

解构 和 展开运算符

解构 {name,age}obj 1. 数组解构 数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法&#xff0c;如下代码所示&#xff1a; <script>// 普通的数组let arr [1, 2, 3];// 批量声明变量 a b c// 同时将数组单元值 1 2 3 依次赋值给变量 a b clet [a, b, c] …