加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Python装饰器的前世今生!

发布时间:2020-12-17 01:17:30 所属栏目:Python 来源:网络整理
导读:p style="margin-top:16px;color:rgb(34,34,34);font-family:'PingFang SC','Hiragino Sans GB','Microsoft YaHei','WenQuanYi Micro Hei','Helvetica Neue',Arial,sans-serif;background-color:rgb(255,255,255);" p style="margin-top:16px;color:rgb(34,2

<p style="margin-top:16px;color:rgb(34,34,34);font-family:'PingFang SC','Hiragino Sans GB','Microsoft YaHei','WenQuanYi Micro Hei','Helvetica Neue',Arial,sans-serif;background-color:rgb(255,255,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">这样做逻辑上是没问题的,功能是实现了,但是我们调用的时候不再是调用真正的业务逻辑today函数,而是换成了logging_tool函数,这就破坏了原有的代码结构,为了支持日志功能,原有代码需要大幅修改,那么有没有更好的方式的呢?当然有,答案就是装饰器。

<p style="margin-top:16px;color:rgb(34,255);">二、开天辟地

<p style="margin-top:16px;color:rgb(34,255);">一个简单的装饰器

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">以上也是装饰器的原理!!!

<p style="margin-top:16px;color:rgb(34,255);">三、Pythonic世界的初探

<p style="margin-top:16px;color:rgb(34,255);">@语法糖 接触 Python 有一段时间的话,对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖,它放在函数开始定义的地方,这样就可以省略最后一步再次赋值的操作

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">有了 @ ,我们就可以省去today = logging_tool(today)这一句了,直接调用 today() 即可得到想要的结果。 不需要对today() 函数做任何修改,只需在定义的地方加上装饰器 ,调用的时候还是和以前一样。 如果我们有其他的类似函数,可以继续调用装饰器来修饰函数 ,而不用重复修改函数或者增加新的封装。这样,提高程序可重复利用性,并增加程序的可读性。

<p style="margin-top:16px;color:rgb(34,255);">装饰器在 Python 使用之所以如此方便,归因于 Python函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">2、让装饰器同时支持带参数或不带参数

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">如上所示,参数有两种类型,一种是字符串,另一种是可调用的函数类型。因此,通过对参数类型的判断即可实现支持带参数和不带参数的两种情况。

<p style="margin-top:16px;color:rgb(34,255);">3、类装饰器

<p style="margin-top:16px;color:rgb(34,255);">装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的call方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

<p style="margin-top:16px;color:rgb(34,255);">(1)示例一、被装饰函数不带参数

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">(3)示例三、不依赖初始化函数,单独使用call函数实现(体现类装饰器灵活性大、高内聚、封装性高的特点) 实现当一些重要函数执行时,打印日志到一个文件中,同时发送一个通知给用户

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">进一步扩展,给LogTool创建子类,来添加email的功能:

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">4、装饰函数 -> 装饰类

<p style="margin-top:16px;color:rgb(34,255);">(1)函数层面的装饰器很常见,以一个函数作为输入,返回一个新的函数; (2)类层面的装饰其实也类似,已一个类作为输入,返回一个新的类;

<p style="margin-top:16px;color:rgb(34,255);">例如:给一个已有的类添加长度属性和getter、setter方法

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">五、上古神器

<p style="margin-top:16px;color:rgb(34,255);">1、@property -> getter/setter方法

<p style="margin-top:16px;color:rgb(34,255);">示例:给一个Student添加score属性的getter、setter方法

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">2、@classmethod、@staticmethod

<p style="margin-top:16px;color:rgb(34,255);">(1)@classmethod 类方法:定义备选构造器,第一个参数是类本身(参数名不限制,一般用cls) (2)@staticmethod 静态方法:跟类关系紧密的函数

<p style="margin-top:16px;color:rgb(34,255);">简单原理示例:

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">3、@functools.wraps

<p style="margin-top:16px;color:rgb(34,255);">装饰器极大地复用了代码,但它有一个缺点:因为返回的是嵌套的函数对象wrapper,不是原函数,导致原函数的元信息丢失,比如函数的docstring、?<span style="font-weight:700;">name?、参数列表等信息。不过呢,办法总比困难多,我们可以通过@functools.wraps将原函数的元信息拷贝到装饰器里面的func函数中,使得装饰器里面的func和原函数有一样的元信息。

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">@functools.wraps让我们可以通过属性wrapped直接访问被装饰的函数,同时让被装饰函数正确暴露底层的参数签名信息

<pre style="font-family:Consolas,Menlo,Courier,monospace;font-size:16px;white-space:normal;color:rgb(34,34);background-color:rgb(255,255);">countdown.wrapped(1000) # 访问被装饰的函数print(inspect.signature(countdown)) # 输出被装饰函数的签名信息<p style="margin-top:16px;color:rgb(34,255);">4、Easter egg

<p style="margin-top:16px;color:rgb(34,255);">(1) 定义一个接受参数的包装器

<pre style="font-family:Consolas,255);">@decorator(x,y,z)def func(a,b):pass<p style="margin-top:16px;color:rgb(34,255);">等价于

<pre style="font-family:Consolas,255);">func = decorator(x,z)(func)<p style="margin-top:16px;color:rgb(34,255);">即:decorator(x,z)的返回结果必须是一个可调用的对象,它接受一个函数作为参数并包装它。

<p style="margin-top:16px;color:rgb(34,255);">(2)一个函数可以同时定义多个装饰器,比如:

<p style="margin-top:16px;color:rgb(34,255);">

Python装饰器的前世今生!

<p style="margin-top:16px;color:rgb(34,255);">欢迎关注我的博客或者公众号:https://home.cnblogs.com/u/Python1234/ Python学习交流

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读