Python Decorator装饰器的创建方法及常用场景分析
作者:什么都干的派森 发布时间:2022-05-05 03:34:11
标签:Python,Decorator,装饰器
前言
1.装饰器本质是一个语法糖,是对被装饰方法或类进行的功能扩充,是一种面向切面的实现方法
2.装饰器可以分成方法装饰器和类装饰器,他们的区别是一个是用函数实现的装饰器,一个是用类实现的装饰器,他们也都能在方法和类上进行装饰
3.类装饰器看起来结构更加清晰,因此下面的代码实现的装饰器全是类装饰器
一、创建方式
1.创建“装饰方法”的类装饰器
from functools import wraps
# 装饰器类
class MyDecorator(object):
def __init__(self, plusNum):
self.plusNum = plusNum # 装饰器入参
def __call__(self, func):
@wraps(func) # @wraps保证装饰器不改变被装饰方法的原有函数结构
def wrapped_function(*args, **kwargs):
# 调用被装饰方法前执行一些操作 ---------------
# 如果不加@wraps,此处打印结果将是
funcName = func.__name__
print("funcName: {}".format(funcName))
# ---------------------------------------
# 修改被装饰方法的入参 --
num1 = args[0] + 2
num2 = args[1] + 3
args = (num1, num2)
# -------------------
# 执行被装饰方法 -------------
res = func(*args, **kwargs)
# -------------------------
# 调用被装饰方法后执行一些操作 -------------
print("do something after the func...")
# -------------------------------------
# 修改被装饰方法的出参 --
res += self.plusNum
# -------------------
# 返回被装饰方法的参数
return res
# 返回装饰器方法
return wrapped_function
# 被装饰的方法
@MyDecorator(3)
def add(num1, num2):
return num1+num2
if __name__ == '__main__':
# 整体执行流程:
# 1. 打印 add 方法名
# 2. 修改被装饰方法入参
# 3. 执行被装饰方法
# 4. 调用被装饰方法后执行一些操作
# 5. 修改被装饰方法的出参
# 6. 打印结果
print(add(5, 3))
# funcName: add
# do something after the func...
# 16
2.创建“装饰类中方法”的类装饰器
from functools import wraps
# 装饰器类
class MyDecorator(object):
def __init__(self, plusNum):
self.plusNum = plusNum # 装饰器入参
def __call__(self, func):
@wraps(func) # @wraps保证装饰器不改变被装饰方法的原有函数结构
def wrapped_function(*args, **kwargs):
# 此处与直接装饰方法相同
# 调用被装饰方法前执行一些操作 ---------------
# 如果不加@wraps,此处打印结果将是
funcName = func.__name__
print("funcName: {}".format(funcName))
# ---------------------------------------
# 此处需要注意,如果需要修改入参的值,那么传参的索引是从1开始而不是从0开始,因为第一个入参的值是实例本身self
# 修改被装饰方法的入参 --
num1 = args[1] + 2
num2 = args[2] + 3
args = (args[0], num1, num2)
# -------------------
# 此处与直接装饰方法相同
# 执行被装饰方法 -------------
res = func(*args, **kwargs)
# -------------------------
# 此处与直接装饰方法相同
# 调用被装饰方法后执行一些操作 -------------
print("do something after the func...")
# -------------------------------------
# 此处与直接装饰方法相同
# 修改被装饰方法的出参 --
res += self.plusNum
# -------------------
# 返回被装饰方法的参数
return res
# 返回装饰器方法
return wrapped_function
class Operation(object):
# 被装饰的类方法
@MyDecorator(3)
def add(self, num1, num2):
return num1+num2
if __name__ == '__main__':
op = Operation()
print(op.add(3, 5))
# funcName: add
# do something after the func...
# 16
3.创建“装饰类”的类装饰器
from functools import wraps
# 装饰器类
class MyDecorator(object):
def __init__(self, plusNum):
self.plusNum = plusNum # 装饰器入参
def __call__(self, Cls):
@wraps(Cls) # @wraps保证装饰器不改变被装饰类的原有结构
def wrapped_function(*args, **kwargs):
# 调用被装饰类前执行一些操作 ---------------
# 如果不加@wraps,此处打印结果将是
clsName = Cls.__name__
print("clsName: {}".format(clsName))
# ---------------------------------------
# 修改被装饰类的入参 ---
num1 = args[0] + 2
num2 = args[1] + 3
args = (num1, num2)
# -------------------
# 初始化被装饰类 -------------
cls = Cls(*args, **kwargs)
# -------------------------
# 初始化后执行一些操作 --------------------
print("do something after the func...")
# -------------------------------------
# 给类实例增加增加属性和方法 ---------------------
cls.mul = 3 # 增加属性
cls.plusNumber = self.plusNumber # 增加方法
# -------------------------------------------
# 返回实例
return cls
# 返回装饰器方法
return wrapped_function
def plusNumber(self, num):
return num + self.plusNum
# 被装饰的类
@MyDecorator(3)
class Operation(object):
def __init__(self, num1, num2):
self.num1 = num1
self.num2 = num2
def add(self):
num3 = self.num1 + self.num2
num4 = self.plusNumber(num3*self.mul) # 使用装饰器插入的属性和方法
return num4
if __name__ == '__main__':
# 整体执行流程:
# 1. 打印 Operation 类名
# 2. 修改类的初始化参数
# 3. 初始化类
# 4. 初始化完成后执行一些方法
# 5. 给初始化的实例新增 mul 属性和 plusNumber 方法
# 6. 实例执行 add 函数并调用新增的装饰函数和装饰属性
# 7. 输出结果
op = Operation(3, 5)
print(op.add())
# clsName: Operation
# do something after the func...
# 42
二、常用场景
1.记录日志
# todo
2.性能测试
# todo
3.循环执行
# todo
4. *
# todo
5.数据预处理(数据清洗)
# todo
6.功能植入
# todo
来源:https://blog.csdn.net/weixin_43721000/article/details/125590006


猜你喜欢
- Golang中Array是值类型而slice是引用类型。因此两者之间的赋值或拷贝有些差异,本文带你了解各自的差异。1. 拷贝array前面提
- 一.做数据二.搭建神经网络三.训练四.对比测试结果注意:测试过程中,一定要注意模式切换Pytorch的学习——过拟合过拟合过拟合是当数据量较
- 本文实例讲述了Flask框架 CSRF 保护实现方法。分享给大家供大家参考,具体如下:Flask CSRF 保护为什么需要 CSRF?具体操
- requests接口测试的介绍requests是一个很实用的Python HTTP客户端库,编写爬虫和测试服务器响应数据时经常会用到,Req
- 先看一个js函数 function jsontest() { var json = [{'username':'cr
- 1 计算属性实现模糊查询vue 中通过计算属性实现模糊查询,创建 html 文件,代码直接放入即可。这里自己导入 vue,我是导入本地已经下
- 今天来分享一个“高大上”的技术——使用python编写一个可以用微信远程控制电脑的程序!先来分析一下控制的具体流程:我们使用微信给特定的邮箱
- select * from table limit m,n其中m是指记录开始的index,从0开始,n是指从第m条开始,取n条。mysql(
- 框架特色:一、统一命名空间 默认命名空间为F,当然你也可以改成自己喜欢的名字,整个框架
- 本文内容皆为作者原创,码字不易,如需转载,请注明出处:https://www.cnblogs.com/temari/p/13048977.h
- 百度的资料,保存下来:在写按时间段查询的sql语句的时候 一般我们会这么写查询条件:where date>='2010-01-
- 本文实例讲述了Python回文字符串及回文数字判定功能。分享给大家供大家参考,具体如下:所谓回文字符串,就是一个字符串,从左到右读和从右到左
- 本文实例为大家分享了python实现维吉尼亚算法的具体代码,供大家参考,具体内容如下1 Virginia加密算法、解密算法Vigenenre
- 一、问题描述在用python开发时经常用到logging这个包,根据官方示例,如果要指定日志级别可以写成如下的方式。import loggi
- Python元字典字典(dictionary)是除列表以外python之中最灵活的内置数据结构类型。列表是有序的对象结合,字典是无序的对象集
- 一、什么是v-bind指令v-bind指令用于响应更新HTML特性,允许将一个或多个属性动态绑定到表达式。v-bind是应用在动态属性上面的
- 当我们的程序报错时,解释器会将整个异常的堆栈信息全部输出出来,举个例子:def foo(): &
- 对于英文不行我来说使用英文版PyCharm实在是太难受了,网上好多汉化补丁都是网友提供了,下面为大家介绍一种PyCharm官方中文语言包汉化
- 背景golang 中主推 channel 通信。单个 channel 的通信可以通过一个goroutine往 channel 发数据,另外一
- JavaScript中indexOf函数方法是返回 String 对象内第一次出现子字符串的字符位置。使用方法:strObj.indexOf