当前位置: 首页 > news >正文

[python入门㊻] - python装饰器和类的装饰器

目录

❤  python装饰器介绍

❤  什么是装饰器

❤  装饰器的流程

❤  定义装饰器时通常会涉及以下3个函数

无参装饰器

有参装饰器

多重装饰器

❤  装饰器的用法(闭包)

❤  装饰器语法糖

❤  时间计时器

❤  装饰器中@wraps作用

不使用@wraps装饰器

使用@wraps装饰器解决这个问题

❤  装饰器顺序 

❤  类的装饰器 - classmethod

绑定到对象的方法

绑定到类的方法

❤  类的装饰器 - property

❤  类的装饰器 - staticmethod 


❤  python装饰器介绍

  1. 在Python中,装饰器(decorator)是在闭包的基础上发展起来的。
  2. 装饰器的实质是一个高阶函数,其参数是要装饰的函数名,其返回值是完成装饰的函数名,其作用是为已经存在的函数对象添加额外的功能,其特点是不需要对原有函数做任何代码上的变动。
  3. 装饰器在本质上也是一个嵌套函数,其外层函数的返回值是一个新的函数对象引用,所不同的是,其外层函数可以接受一个现有函数对象引用作为参数
  4. 装饰器可以用于包装现有函数,即在不修改任何代码的前提下为现有函数增加额外功能
  5. 装饰器通常应用于有切面面向切面编程是指运行时动态实现程序维护的一种技术)需求的场景,例如插入日志、性能测试、事务处理、缓存以及权限校验等。
  6. 装饰器是解决这类问题的绝佳设计,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用它们。

❤  什么是装饰器

装饰是为函数指定管理代码的一种方式。Python装饰器以两种形式呈现:

  • 函数装饰器在函数定义的时候进行名称重绑定。提供一个逻辑层来管理函数和方法或随后对它们的调用。
  • 类装饰器在类定义的时候进行名称重绑定,提供一个逻辑层来管理类。或管理随后调用它们所创建的实例。

❤  装饰器的流程

  • A函数是装饰器,B函数是A函数传入的参数
  • 将B函数在A函数中执行,在A函数中可以选择执行或不执行,也可以对B函数的结果进行二次加工处理

简而言之,装饰器提供了一种方法,在函数和类定义语句的末尾插入自己主动执行的代码——对于函数装饰器。在def的末尾。对于类装饰器,在class的末尾。

这种代码能够扮演不同的角色。
装饰器提供了一些和代码维护性和审美相关的有点。此外,作为结构化工具,装饰器自然地促进了代码封装,这降低了冗余性并使得未来变得更easy。

❤  定义装饰器时通常会涉及以下3个函数:

1)装饰器函数:它在函数嵌套关系中作为外层函数出现,其函数体内容包括定义一个内层函数以完成装饰功能的函数,通过return语句向调用者返回内层函数对象引用。
2)目标函数:即需要进行装饰的函数,它作为装饰器函数的形参出现,该函数的定义则出现在调用装饰器的地方。
3)完成装饰的函数:它在函数嵌套关系中作为内层函数出现,用于为待装饰的目标函数添加额外功能。在这个内层函数中要调用目标函数,并为目标函数添加一些新的功能

无参装饰器

def 装饰器名称(待装饰器函数名称):def 装饰器函数名称():# 目标函数执行前 添加额外功能# 目标函数调用 待装饰器函数执行# 目标函数执行后 添加额外功能return 装饰器函数名称def decorator(func):def inner(*args, **kwargs):# func是被装饰的对象,这里可以写执行前的功能res = func(*args, **kwargs)# func是被装饰的对象,这里可以写执行后的功能return inner# 使用装饰器@装饰器名称
def 需装饰函数名称():pass

无参数装饰器本质就是一个双层结构的高阶函数,有参数装饰器则是一个3层结构的高阶函数。

有参装饰器

def 装饰器名称(参数1, 参数2,...):def 中间层装饰器函数名称(待装饰器函数名称)def 里层装饰器函数名称():# 目标函数执行前 添加额外功能# 目标函数调用 待装饰器函数执行# 目标函数执行后 添加额外功能return 装饰器函数名称return 中间层装饰器函数名称def decorator(arg1, arg2):def middle(func):def inner(*args, **kwargs):# func是被装饰的对象,这里可以写执行前的功能 可使用参数 arg1, arg2res = func(*args, **kwargs)# func是被装饰的对象,这里可以写执行后的功能 可使用参数 arg1, arg2return innerreturn middle# 使用装饰器@装饰器名称(arg1, arg2)
def 需装饰函数名称():pass

多重装饰器

多重装饰器是指使用多个装饰器来修改同一个函数。此时要注意多重装饰器的执行顺序是后面的装饰器先执行,前面的装饰器后执行,即后来者居上

def first(func):def inner(*args, **kwargs):print("函数:first执行...")func(*args, **kwargs)print("函数:first完成")return innerdef second(func):def inner(*args, **kwargs):print("函数:second执行...")func(*args, **kwargs)print("函数:second完成")return inner# 两装饰器应用于同一函数@first
@second
def test():print("函数:test执行")# 执行结果
"""
函数:first执行...
函数:second执行...
函数:test执行
函数:second完成
函数:first完成
"""

❤  装饰器的用法(闭包)

闭包(Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数

这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

def print_msg():  # print_msg是外围函数msg = "I'm closure"def printer():  # printer是嵌套函数print(msg)return printerclosure = print_msg()  # 这里获得的就是一个闭包
closure()  # 输出 I'm closure

msg是一个局部变量,在print_msg函数执行之后就不会存在了。

但是嵌套函数引用了这个变量,将这个局部变量封闭在了嵌套函数中,这样就形成了一个闭包。

❤  装饰器语法糖

语法糖(Syntactic sugar),也译为糖衣语法,指计算机语言中添加的某种语法。

这种语法对语言的功能并没有影响,但是更方便程序员使用。

通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

@ 符号是装饰器的语法糖。它放在一个函数开始定义的地方(头顶),和这个函数绑定在一起。

在我们调用这个函数的时候,会先将这个函数做为参数传入它头顶,即装饰器里。

❤  时间计时器

以下用装饰器来实现计算一个函数的执行时长,让函数睡眠3秒

# 这是装饰函数
def timer(func):def wrapper(*args, **kw):start_time = time.time()func(*args, **kw)  # 这是函数真正执行的地方stop_time = time.time()cost_time = stop_time - start_timeprint("花费时间:{}秒".format(cost_time))return wrapperimport time@timer
def want_sleep(sleep_time):time.sleep(sleep_time)want_sleep(3)

❤  装饰器中@wraps作用

装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)。

为了不影响,Python的functools包中提供了一个叫wraps的装饰器来消除这样的副作用。

写一个装饰器的时候,最好在实现之前加上functools中的wraps,它能保留原有函数的名称和文档字符串(DocStrings)。

文档字符串用于解释文档程序,帮助程序文档更加简单易懂。

可以在函数体的第一行使用一对三个单引号 ‘’’ 或者一对三个双引号 “”" 来定义文档字符串。

使用 doc(注意双下划线)调用函数中的文档字符串属性。

不使用@wraps装饰器

def decorator(func):"""this is decorator __doc__"""def wrapper(*args, **kwargs):"""this is wrapper __doc__"""print("this is wrapper method")return func(*args, **kwargs)return wrapper@decorator
def test():"""this is test __doc__"""print("this is test method")print("__name__: ", test.__name__)
print("__doc__:  ", test.__doc__)

输出:

__name__:  wrapper
__doc__:   this is wrapper __doc__

分析:
对test()方法进行装饰时候,实际上是

test = decorator(test)

返回的是wrapper方法的引用,也就是让test指向了wrapper方法,所以调用test.name, 实际上是wrapper.name

这造成后面查找该方法的名字和注释时得到装饰器内嵌函数的名字和注释

使用@wraps装饰器解决这个问题

from functools import wrapsdef decorator(func):"""this is decorator __doc__"""@wraps(func)def wrapper(*args, **kwargs):"""this is wrapper __doc__"""print("this is wrapper method")return func(*args, **kwargs)return wrapper@decorator
def test():"""this is test __doc__"""print("this is test method")print("__name__: ", test.__name__)
print("__doc__:  ", test.__doc__)

输出:

__name__:  test
__doc__:   this is test __doc__

❤  装饰器顺序 

一个函数可以同时定义多个装饰器,比如:

@a
@b
@c
def f ():pass

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于:

f = a(b(c(f)))

❤  类的装饰器 - classmethod

@classmethod: *****
类的对象绑定的方法都是默认传self参数的,但是当这个self在方法中不被使用时,
然后在方法中准备使用类的静态属性,就可以将该方法修改为类方法
在外部可以不用实例化对象直接通过类名调用类方法

绑定到对象的方法:

在类内部没有任何修饰的情况下直接定义一个方法默认绑定一个self给对象来用

class Mysql:def __init__(self,host,port):self.host=hostself.port=portdef tell_info(self):  print("<%s:%s>" %(self.host,self.port))conn1=Mysql('127.0.0.1',8080)
conn1.tell_info()

输出:

<127.0.0.1:8080> 

绑定到类的方法:

当函数体代码需要传进来的参数不再是对象了,而是类的时候

以下是实现从配置文件里读IP和端口,完成实例化的程序:

settings

import settingsclass Mysql:def __init__(self,host,port):self.host=hostself.port=portdef tell_info(self):print("<%s:%s>" %(self.host,self.port))@classmethod   #绑定给类,由类来掉,把它当做第一个参数传进来完成实例化,再把结果返回def from_conf(cls):return cls(settings.HOST, settings.PORT)conn2=Mysql.from_conf()print(conn2.tell_info)
conn2.tell_info()# 打印结果:<bound method Mysql.tell_info of <__main__.Mysql object at 0x00C9CFF0>>          <1.1.1.1:8080>

我们得出以下结论:

  • 在带有 classmethod 装饰器 的 函数 内,是无法调用普通的 带有 self 的函数的
  • 但是在普通的带有 self 的类函数内,是可以调用带有 classmethod 装饰器 的 函数的

 ❤  类的装饰器 - property

property是一种特殊的属性,可实现把函数名变为属性名使用。它可以在不改变类接口的前提下使用存取方法 (即读值和取值)

来修改数据的属性,property类有3个方法getter(读操作)、setter(赋值操作)、deleter(删除操作),分别把对应的操作

绑定到指定的函数实现,应用如下:

class People:def __init__(self,name,weight,height):self.name=nameself.wt=weightself.ht=height@propertydef bmi(self):return self.wt / (self.ht ** 2)@property     #便于用户访问隐藏的内部值namedef name(self):return self.__name@name.setter   #便于用户 修改name值def name(self,obj): #obj='EGON'if not isinstance(obj,str):raise TypeError('名字的值必须是str类型')self.__name=obj #self.__name='EGON'@name.deleterdef name(self):del self.__namep=People('egon',75,1.80)
# print(p.bmi)# print(p.name)
# p.name='EGON'
# p.name=123       #报错
# print(p.name)# del p.name   #删除name

❤  类的装饰器 - staticmethod 

非绑定方法,不与任何东西绑定,定义的函数不需要任何东西传进来

import uuidclass Mysql:def __init__(self,host,port):self.host=hostself.port=port@staticmethoddef create_id():return uuid.uuid4()print(Mysql.create_id)
print(Mysql.create_id())#打印结果:<function Mysql.create_id at 0x02C6EC90>         2209806a-5ffc-47f2-86f1-cb2ac64ce404

整体代码:

import settings
import uuidclass Mysql:def __init__(self,host,port):self.host=hostself.port=portdef tell_info(self):print("<%s:%s>" %(self.host,self.port))@classmethoddef from_conf(cls):return cls(settings.HOST, settings.PORT)@staticmethoddef create_id():return uuid.uuid4()conn1=Mysql('127.0.0.1',8080)
conn1.tell_info()conn2=Mysql.from_conf()
conn2.tell_info()
print(conn2.tell_info)print(Mysql.create_id)
print(Mysql.create_id())#打印结果:<127.0.0.1:8080>         <1.1.1.1:8080>         <bound method Mysql.tell_info of <__main__.Mysql object at 0x038294B0>>         <function Mysql.create_id at 0x03831E40>         bab5e25e-7de3-4273-a8cf-40829c716d87

附:使用最广泛的装饰器为 classmethod

相关文章:

[python入门㊻] - python装饰器和类的装饰器

目录 ❤ python装饰器介绍 ❤ 什么是装饰器 ❤ 装饰器的流程 ❤ 定义装饰器时通常会涉及以下3个函数 无参装饰器 有参装饰器 多重装饰器 ❤ 装饰器的用法(闭包) ❤ 装饰器语法糖 ❤ 时间计时器 ❤ 装饰器中wraps作用 不使用wraps装饰器 使用wraps装饰器解…...

企业级信息系统开发学习1.1 初识Spring——采用Spring配置文件管理Bean

文章目录一、Spring容器演示——采用Spring配置文件管理Bean&#xff08;一&#xff09;创建Maven项目&#xff08;二&#xff09;添加Spring依赖&#xff08;三&#xff09;创建杀龙任务类&#xff08;四&#xff09;创建勇敢骑士类&#xff08;五&#xff09;采用传统方式让勇…...

CSS盒子模型

盒子模型 CSS三大特性 继承性、层叠性、优先级 优先级比较 继承 < 通配符选择器 < 标签选择器 < 类选择器 < id选择器 < 行内样式 < !important 注意&#xff1a;!important不能提升继承的优先级&#xff0c;只要是继承优先级最低 复合选择器权重叠加计…...

Python基础学习笔记 —— 数据结构与算法

数据结构与算法1 数据结构基础1.1 数组1.2 链表1.3 队列1.4 栈1.5 二叉树2 排序算法2.1 冒泡排序2.2 快速排序2.3 &#xff08;简单&#xff09;选择排序2.4 堆排序2.5 &#xff08;直接&#xff09;插入排序3 查找3.1 二分查找1 数据结构基础 本章所需相关基础知识&#xff1a…...

笔记本连接wifi,浏览器访问页面,显示访问被拒绝

打开chrome、edge浏览器访问第1个第2个页面正常&#xff0c;后面再打开页面显示异常。 但手机连接正常&#xff0c;笔记本连接异常&#xff0c;起初完全没有怀疑是wifi问题 以为用了vpn软件问题&#xff0c;认为中了病毒。杀毒&#xff0c;并没有中毒。 1、关闭vpn代理&#…...

36个物联网专业毕业论文选题推荐

物联网技术在智能家居系统中的应用研究物联网在智慧城市建设中的作用物联网在工业4.0中的实现与发展 物联网与智能物流系统的结合物联网与医疗健康领域的融合研究物联网与环境监测系统的集成物联网与农业生产的结合研究物联网技术对汽车行业的影响与发展物联网在智能安防领域的…...

Pytorch复习笔记--torch.nn.functional.interpolate()和cv2.resize()的使用与比较

1--前言 博主在处理图片尺度问题时&#xff0c;习惯使用 cv2.resize() 函数&#xff1b;但当图片数据需用显卡加速运算时&#xff0c;数据需要在 GPU 和 CPU 之间不断迁移&#xff0c;导致程序运行效率降低&#xff1b; Pytorch 提供了一个类似于 cv2.resize() 的采样函数&…...

ASP.NET Core MVC 项目 AOP之ActionFilterAttribute

目录 一:说明 二:实现ActionFilterAttribute父类 一:说明 ActionFilterAttribute比前两者简单方便,易于扩展,不易产生代码冗余。 ActionFilterAttribute过滤器执行顺序: 1:执行控制器中的构造函数,实例化控制器 2:执行ActionFilterAttribute.OnActionExecutionA…...

浅析EasyCVR安防视频能力在智慧小区建设场景中的应用及意义

一、行业需求 城市的发展创造了大量工作机会&#xff0c;人口的聚集也推动了居民住宅建设率的增长。人民生活旨在安居乐业&#xff0c;能否住得“踏实”是很多劳动工作者最关心的问题。但目前随着住宅小区规模的不断扩大、人口逐渐密集&#xff0c;在保证居住环境舒适整洁的同…...

Python的深、浅拷贝到底是怎么回事?一篇解决问题

嗨害大家好鸭&#xff01;我是小熊猫~ 一、赋值 Python中&#xff0c; 对象的赋值都是进行对象引用&#xff08;内存地址&#xff09;传递, 赋值&#xff08;&#xff09;&#xff0c; 就是创建了对象的一个新的引用&#xff0c; 修改其中任意一个变量都会影响到另一个 will …...

TCP协议十大特性

日升时奋斗&#xff0c;日落时自省 目录 1、确认应答 1.1、序号编辑 2、超时重传 3、连接管理 3.1、三次握手 3.2、四次挥手 4、滑动窗口 5、流量控制 6、拥塞控制 7、延时应答 8、捎带应答 9、面向字节流 10、异常情况 TCP协议&#xff1a; 特点&#xff1a;有…...

2.14作业【GPIIO控制LED】

设备树 myleds{ myled1 <&gpioe 10 0>; myled2 <&gpiof 10 0>; myled3 <&gpioe 8 0>; }; 驱动代码 #include<linux/init.h> #include<linux/module.h> #include<linux/of.h&…...

5min搞定linux环境Jenkins的安装

5min搞定linux环境Jenkins的安装 安装Jenkinsstep1: 使用wget 命令下载Jenkinsstep2、创建Jenkins日志目录并运行jekinsstep3、访问jenkins并解锁jenkins,安装插件以及创建管理员用户step4、到此,就完成了Finish、以上步骤中遇到的问题1、 jenkins启动不了2、jenkins无法访问…...

Cortex-M0存储器系统

目录1.概述2.存储器映射3.程序存储器、Boot Loader和存储器重映射4.数据存储器5.支持小端和大端数据类型数据对齐访问非法地址多寄存器加载和存储指令的使用6.存储器属性1.概述 Cortex-M0处理器具有32位系统总线接口&#xff0c;以及32位地址线&#xff08;4GB的地址空间&…...

软件测试——测试用例之场景法

一、场景法的应用场合 场景法主要用于测试软件的业务流程和业务逻辑。场景法是基于软件业务的测试方法。在场景法中测试人员把自己当成最终用户&#xff0c;尽可能真实的模拟用户在使用此软件的操作情景&#xff1a; 重点模拟两类操作&#xff1a; 1&#xff09;模拟用户正确…...

英文写作中的常用的衔接词

1. 增补 (Addition) in addition, furthermore, again, also, besides, moreover, whats more, similarly, next, finally 2.比较&#xff08;Comparision&#xff09; in the same way, similarly, equally, in comparison, just as 3. 对照 (Contrast) in contrast, on …...

新库上线 | CnOpenData中国地方政府债券信息数据

中国地方政府债券信息数据 一、数据简介 地方政府债券 指某一国家中有财政收入的地方政府地方公共机构发行的债券。地方政府债券一般用于交通、通讯、住宅、教育、医院和污水处理系统等地方性公共设施的建设。地方政府债券一般也是以当地政府的税收能力作为还本付息的担保。地…...

Python 条件语句

Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空&#xff08;null&#xff09;值为true&#xff0c;0 或者 null为false。 Python 编…...

C语言思维导图大总结 可用于期末考试 C语言期末考试题库

目录 一.C语言思维导图 二.C语言期末考试题库 一.C语言思维导图 导出的图可能有点糊&#xff0c;或者查看链接&#xff1a;https://share.weiyun.com/uhf1y2mp 其实原图是彩色的不知道为什么导出时颜色就没了 部分原图&#xff1a; 也可私信我要全图哦。 图里的链接可能点不…...

从零实现深度学习框架——再探多层双向RNN的实现

来源&#xff1a;投稿 作者&#xff1a;175 编辑&#xff1a;学姐 往期内容&#xff1a; 从零实现深度学习框架1&#xff1a;RNN从理论到实战&#xff08;理论篇&#xff09; 从零实现深度学习框架2&#xff1a;RNN从理论到实战&#xff08;实战篇&#xff09; 从零实现深度…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...