Python装饰器的前世今生!

Python装饰器的前世今生!

Python装饰器的前世今生!

这样做逻辑上是没问题的,功能是实现了,但是我们调用的时候不再是调用真正的业务逻辑today函数,而是换成了logging_tool函数,这就破坏了原有的代码结构,为了支持日志功能,原有代码需要大幅修改,那么有没有更好的方式的呢?当然有,答案就是装饰器。

二、开天辟地

一个简单的装饰器

Python装饰器的前世今生!

以上也是装饰器的原理!!!

三、Pythonic世界的初探

@语法糖 接触 Python 有一段时间的话,对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖,它放在函数开始定义的地方,这样就可以省略最后一步再次赋值的操作

Python装饰器的前世今生!

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

装饰器在 Python 使用之所以如此方便,归因于 Python函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

Python装饰器的前世今生!

Python装饰器的前世今生!

2、让装饰器同时支持带参数或不带参数

Python装饰器的前世今生!

如上所示,参数有两种类型,一种是字符串,另一种是可调用的函数类型。因此,通过对参数类型的判断即可实现支持带参数和不带参数的两种情况。

3、类装饰器

装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

(1)示例一、被装饰函数不带参数

Python装饰器的前世今生!

(3)示例三、不依赖初始化函数,单独使用__call__函数实现(体现类装饰器灵活性大、高内聚、封装性高的特点) 实现当一些重要函数执行时,打印日志到一个文件中,同时发送一个通知给用户

Python装饰器的前世今生!

进一步扩展,给LogTool创建子类,来添加email的功能:

Python装饰器的前世今生!

4、装饰函数 -> 装饰类

(1)函数层面的装饰器很常见,以一个函数作为输入,返回一个新的函数; (2)类层面的装饰其实也类似,已一个类作为输入,返回一个新的类;

例如:给一个已有的类添加长度属性和getter、setter方法

Python装饰器的前世今生!

五、上古神器

1、@property -> getter/setter方法

示例:给一个Student添加score属性的getter、setter方法

Python装饰器的前世今生!

2、@classmethod、@staticmethod

(1)@classmethod 类方法:定义备选构造器,第一个参数是类本身(参数名不限制,一般用cls) (2)@staticmethod 静态方法:跟类关系紧密的函数

简单原理示例:

Python装饰器的前世今生!

3、@functools.wraps

装饰器极大地复用了代码,但它有一个缺点:因为返回的是嵌套的函数对象wrapper,不是原函数,导致原函数的元信息丢失,比如函数的docstring、 name 、参数列表等信息。不过呢,办法总比困难多,我们可以通过@functools.wraps将原函数的元信息拷贝到装饰器里面的func函数中,使得装饰器里面的func和原函数有一样的元信息。

Python装饰器的前世今生!

@functools.wraps让我们可以通过属性__wrapped__直接访问被装饰的函数,同时让被装饰函数正确暴露底层的参数签名信息

countdown.__wrapped__(1000) # 访问被装饰的函数print(inspect.signature(countdown)) # 输出被装饰函数的签名信息

4、Easter egg

(1) 定义一个接受参数的包装器

@decorator(x, y, z)def func(a, b):pass

等价于

func = decorator(x, y, z)(func)

即:decorator(x, y, z)的返回结果必须是一个可调用的对象,它接受一个函数作为参数并包装它。

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

Python装饰器的前世今生!

欢迎关注我的博客或者公众号:https://home.cnblogs.com/u/Python1234/ Python学习交流

猜你喜欢

转载自www.cnblogs.com/Python1234/p/9102039.html
今日推荐